Я создал интерфейс TwoMethods. Исходный код:

interface TwoMethods<T>
{
    public void method(T t);
}

Затем я создал класс, реализующий этот интерфейс, и после разборки увидел 2 метода. Класс:

class A implements TwoMethods<A>
{
    @Override
    public void method(A a) {}
}

После разборки:

class A implements TwoMethods<A> {
   A();
   public void method(A); //first
   public void method(java.lang.Object); //second
}

Аналогично для интерфейса Comparable. Почему при создании параметризованного интерфейса у меня есть 2 метода. Всегда, когда я использую параметр? У меня есть дополнительный метод с аргументом Object?

16
Pawel 25 Дек 2013 в 14:48

2 ответа

Лучший ответ

Если мы посмотрим на байт-код интерфейса TwoMethods, мы увидим, что на самом деле метод

public abstract method(Ljava/lang/Object;)V

То есть на уровне байт-кода информация о параметре типа не существует, тип удален, JVM просто не знает о дженериках, параметры типа заменяются либо на Object, либо в случае, если T extends X на X. Итак, с точки зрения JVM

class A implements TwoMethods<A> {
    public void method(A a) {
        ...

method(A a) не отменяет метод интерфейса, потому что в байт-коде он находится в method(Object obj) и может его переопределить. Чтобы исправить эту проблему, компилятор создает неявный метод, так называемый метод моста, в классе A.

public void method(Object obj) {
     method((A)obj);
}

Виден только в байт-коде. Теперь для этого кода

A a = new A();
TwoMethods<A> tm = a;
tm.method(a);

Компилятор заменит tm.method(a) вызовом моста

   INVOKEINTERFACE test/TwoMethods.method(Ljava/lang/Object;)V

И это перенаправит вызов на A.method(A a);

15
Evgeniy Dorofeev 25 Дек 2013 в 11:42

method(java.lang.Object) называется методом моста и генерируется из-за стирания типа во время компиляции.

См. Эффекты стирания типов и методов моста

18
Eng.Fouad 25 Дек 2013 в 10:51