调用接口有什么意义?

its*_*dok 65 jvm

我正在阅读这篇关于JVM如何调用方法的文章,我想我已经掌握了大部分内容.但是,我仍然无法理解需要invokeinterface.

我理解它的方式,一个类基本上有一个方法的虚拟表,当调用一个方法时,invokevirtualinvokeinterface咨询这个虚拟表.

那么,在接口上定义的方法和在基类上定义的方法之间有什么区别?为什么不同的字节码?

的指令描述看起来也非常相似.

该文章似乎声称,每次调用方法时,接口的方法表都可以具有"不同的偏移量".我不明白的是为什么接口会有一个方法表,因为没有对象可以将接口作为其实际类型.

我错过了什么?

jan*_*nko 91

每个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() { }
}
Run Code Online (Sandbox Code Playgroud)

结果在表中

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() { }
}
Run Code Online (Sandbox Code Playgroud)

此类层次结构导致虚拟方法表

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被认为是无害的".

  • "总是必须在没有机会进行invokevirtual的优化风格的情况下搜索完整的表格" - 应该注意的是,它并不总是*必须搜索表,因为它可以做不同的优化风格.有关更多详细信息,请参阅链接的"被视为无害"的文章. (5认同)