Какой смысл в invokeinterface? - PullRequest
       7

Какой смысл в invokeinterface?

63 голосов
/ 01 октября 2009

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

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

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

Описание инструкций также выглядит очень похоже.

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

Чего мне не хватает?

Ответы [ 2 ]

89 голосов
/ 01 октября 2009

Каждый класс 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 считается безвредным» .

1 голос
/ 01 октября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...