【问题标题】:What is the point of invokeinterface?调用接口的意义何在?
【发布时间】:2009-10-01 15:27:57
【问题描述】:

我正在阅读this article 关于 JVM 如何调用方法的内容,我想我已经掌握了大部分内容。但是,我仍然无法理解invokeinterface 的需求。

按照我的理解,一个类基本上有一个虚拟方法表,当使用invokevirtualinvokeinterface 调用方法时,会参考这个虚拟表。

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

description of the instructions 看起来也很相似。

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

我错过了什么?

【问题讨论】:

标签: jvm


【解决方案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() { }
}

表格中的结果

基类
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. 另一个类/方法4()
5.MyInterface/ifaceMethod()

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

如您所见,AnotherClass 在其第五个条目中包含接口的方法,MyClass 在其第二个条目中包含它。要真正在虚方法表中找到正确的条目,使用invokeinterface 调用方法总是必须搜索整个表,而没有机会使用invokevirtual 所做的优化风格。

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

【讨论】:

  • "总是必须搜索完整的表,而没有机会使用 invokevirtual 所做的优化风格" -- 需要注意的是,它并不总是必须搜索表,因为它可以做不同风格的优化。有关详细信息,请参阅链接的“认为无害”论文。
  • 那么为什么需要invokeinterface 只使用invokevirtual 呢?
  • @shaoyihe 根据janko的回答,我认为这是为了性能,而invokeinterface不能优化为invokevirtual。原因已经在答案中了(可以实现很多接口,参考表不固定)。
【解决方案2】:

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

【讨论】:

  • 很有趣,但这就是它的全部内容吗?
  • 这有更多的不同(正如其他地方解释的,方法查找过程不同),但这种不同来自接口中的所有方法(至少在 Java 8 之前)都是公共的这一事实.因此,不需要对通过接口访问方法进行可见性检查,因为它们必须是公共的,这意味着所有代码都可以访问它们。
  • 我怀疑它invokespecial will invoke the private 那么检查可访问性是什么?
猜你喜欢
  • 2010-10-23
  • 2016-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 2010-10-07
  • 2011-04-27
相关资源
最近更新 更多