Java final方法使用静态绑定,但JVM在编译时使用“invokevirtual”指令

问题描述 投票:2回答:2

很多书都说java最终实例方法(不是私有)使用静态绑定,而其他实例方法(非私有)使用动态绑定。但是在编译时,它们都使用“invokevirtual”JVM指令。当JVM执行“invokevirtual”指令时,是否区分最终方法和非最终方法?我原本认为最终方法使用“invokespecial”作为私有实例方法,因为它们都使用静态绑定。

java binding static final invokevirtual
2个回答
2
投票

汇编表格是JLS §13.4.17在第13章“二进制兼容性”中的直接结果:

13.4.17. final Methods

将声明为final的方法更改为不再声明为final不会破坏与预先存在的二进制文件的兼容性。

这意味着调用者的形式不应该反映目标方法是否在编译时是final(或者当存在不同的表示时,不允许在运行时产生实际差异)。

为了与其他形式的调用进行比较,不能在不破坏与调用者的兼容性的情况下删除static修饰符,因此,使用专用的invokestatic指令对调用形式进行编码是一致的。

对于private方法的调用,调用者必须在同一个类中,因此,在添加或删除private修饰符时会重新编译(仅考虑有效的调用者),因此在同一个类中调用invokespecial方法时使用private没有问题。从JDK 11开始,private方法可能会被属于同一嵌套组的其他类中的调用者调用;在这种情况下,其他类中的这些调用者不使用invokespecial

所以final和非final方法之间的区别确实在运行时发生,当JVM知道实际的目标方法时,如果发生这样的区别。符合标准的JVM必须拒绝尝试覆盖final方法的类,但它们不需要对调用执行优化。在实践中,今天的JVM能够优化所有尚未被覆盖的方法的调用,无论这些属性是否已由final修饰符强制执行。唯一的区别是将新类加载到JVM中并覆盖非final方法可能会导致调用者的去优化。


0
投票

没有其他字节码指令可以调用由invokevirtual以外的类声明的实例方法。它的名字令人困惑。它也可以命名为invokeClassMethodinvokeclass。实际上编译器不会特别处理最终方法。 invokespecial用于调用构造函数和静态初始化程序。

© www.soinside.com 2019 - 2024. All rights reserved.