В чем смысл invokeinterface?



Я читаю в этой статье о том, как JVM вызывает методы, и я думаю, что я получил большинство из них. Тем не менее, у меня все еще возникают проблемы с пониманием необходимости invokeinterface.



как я понимаю, класс в основном имеет таблицу виртуальных методов и при вызове метода с invokevirtual или invokeinterface эта виртуальная таблица консультируется.



в чем же тогда разница между методом, определенным на интерфейсе, и методом, определенным на базе класс? Почему разные байт-коды?



The описание инструкции также очень похож.



в статье, похоже, утверждается, что таблица методов интерфейса может иметь "разные смещения" каждый раз, когда вызывается метод. Я не понимаю, почему интерфейс будет иметь таблицу методов вообще, так как ни один объект не может иметь интерфейс в качестве его фактического типа.



что я упустил?

557   2  
jvm

2 ответов:

каждый класс Java связан с таблица виртуальных методов, который содержит "ссылки" на байт-код каждого метода класса. Эта таблица наследуется от суперкласса определенного класса и расширяется в отношении новых методов подкласса. Например,

class BaseClass {
    public void method1() { }
    public void method2() { }
    public void method3() { }
}

class NextClass extends BaseClass {
    public void method2() { } // overridden from BaseClass
    public void method4() { }
}

результаты в таблицах

BaseClass
1. BaseClass/method1()
2. BaseClass/method2()
3. BaseClass/method3()

NextClass
1. BaseClass/method1()
2. NextClass/method2()
3. BaseClass/method3()
4. NextClass/method4()

обратите внимание, как виртуальный стол метода NextClass сохраняет порядок записей в таблице BaseClass и просто переписывает ссылку "" из method2(), который он переопределяет.

реализация JVM может таким образом оптимизировать вызов invokevirtual помня, что BaseClass/method3() всегда будет третьей записью в таблице виртуальных методов любого объекта, на котором этот метод когда-либо будет вызван.

С invokeinterface такая оптимизация невозможна. Например,

interface MyInterface {
    void ifaceMethod();
}

class AnotherClass extends NextClass implements MyInterface {
    public void method4() { } // overridden from NextClass
    public void ifaceMethod() { }
}

class MyClass implements MyInterface {
    public void method5() { }
    public void ifaceMethod() { }
}

эта иерархия классов приводит к виртуальным таблицам методов

AnotherClass
1. BaseClass/method1()
2. NextClass/method2()
3. BaseClass/method3()
4. AnotherClass/method4()
5. MyInterface/ifaceMethod()

MyClass
1. MyClass/method5()
2. MyInterface/ifaceMethod()

Как видите, AnotherClass содержит интерфейс метод в его пятой записи и MyClass содержит его во второй записи. Чтобы на самом деле найти правильную запись в таблице виртуальных методов, вызовите метод с invokeinterface всегда придется искать полную таблицу без шанса на стиль оптимизации, что invokevirtual делает.

есть дополнительные различия, как тот факт, что invokeinterface может использоваться вместе со ссылками на объекты, которые фактически не реализуют интерфейс. Таким образом, invokeinterface придется проверить на время выполнения ли метод существует в таблице и потенциально вызвать исключение. Если вы хотите погрузиться глубже в тему, я предлагаю, например,"эффективная реализация интерфейсов Java: Invokeinterface считается безвредным".

сравнение обеих инструкций в JVM Spec, самое первое отличие в том, что invokevirtual проверяет доступность метода, во время просмотра, в то время как invokeinterface нет.

Comments

    Ничего не найдено.