Подтвердить что ты не робот

В чем смысл invokeinterface?

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

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

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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