invokeinterface的意义是什么?


68

我正在阅读有关JVM如何调用方法的文章,并且我想我了解了大部分。但是,我仍然无法理解的需求invokeinterface

我的理解是这样的,一类主要有方法的一个虚拟表,并呼吁与任何一种方法时,invokevirtualinvokeinterface此虚拟表查询。

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

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

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

我想念什么?



1
它具有虚拟方法表。桌子本身根本不是虚拟的;)
Rafael Winterhalter

Answers:


92

每个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() { }
}

表中的结果

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

下一班
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() { }
}

该类层次结构产生虚拟方法表

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

我的课
1. MyClass / method5()
2. MyInterface / ifaceMethod()

如您所见,AnotherClass该接口的方法在其第五项中MyClass包含,而在其第二项中其包含。为了在虚拟方法表中实际找到正确的条目,使用方法进行的调用invokeinterface将始终必须搜索整个表,而没有机会进行优化invokevirtual

还有其他一些差异,例如事实,invokeinterface可以与实际上未实现接口的对象引用一起使用。因此,invokeinterface将必须在运行时检查表中是否存在方法并可能引发异常。


7
“总是必须搜索整个表,而没有机会获得invokevirtual所做的优化风格” –应该指出的是,它不一定总是要搜索表,因为它可以进行不同的优化风格。有关更多详细信息,请参见链接的“认为无害”文件。
布兰登·布鲁姆

那么为什么invokeinterface 只需要使用invokevirtual呢?
shaoyihe

@shaoyihe基于janko的回答,我认为这是为了提高性能,而invokeinterface无法优化为invokevirtual。答案中已经包含了原因(可以实现许多接口,并且参考表不固定)。
聆听

2

比较JVM Spec中的两条指令,第一个区别是invokevirtual在查找过程中检查方法的可访问性,而invokeinterface没有。


有趣,但是那可能就是全部吗?
itsadok

两者之间还有更多的区别(如在其他地方说明的那样,方法查找过程是不同的),但是这种区别来自于接口中的所有方法(至少在Java 8之前)是公共的。因此,不需要对通过接口访问方法的可见性进行检查,因为它们必须是公共的,这意味着所有代码都可以访问它们。
巴里·费根鲍姆

我怀疑它的invokespecial将调用私有的,那么检查可访问性又是什么呢?
聆听
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.