Jvm 使用invokespecial调用公共方法?

Jvm 使用invokespecial调用公共方法?,jvm,Jvm,任何能回答这个问题的人都知道,JVM支持几种字节码指令来调用方法(invokevirtual,invokespecial,invokestatic,…) 对实例方法的大多数方法调用都是通过invokevirtual进行的,但是私有方法和初始化器方法是通过invokespecial进行调用的,如JVM规范中所述: invokevirtual指令与invokevirtual指令之间的区别在于invokevirtual基于对象的类调用方法。invokespecial指令用于调用实例初始化方法以及私有方

任何能回答这个问题的人都知道,JVM支持几种字节码指令来调用方法(
invokevirtual
invokespecial
invokestatic
,…)

对实例方法的大多数方法调用都是通过
invokevirtual
进行的,但是私有方法和初始化器方法是通过
invokespecial
进行调用的,如JVM规范中所述:

invokevirtual
指令与
invokevirtual
指令之间的区别在于
invokevirtual
基于对象的类调用方法。
invokespecial
指令用于调用实例初始化方法以及私有方法和当前类的超类方法

据我所知,
invokevirtual
执行vtable查找来解析方法,而
invokespecial
,因为正确的方法实现在链接时已知,是静态解析的


我的问题是,为什么在编译时已知方法所有者的具体类的情况下,
invokespecial
不用于调用
public
方法?在我看来,出于效率考虑,避免vtable查找是可取的。但是很明显,我对JVM有些不了解。

首先,在编译时要知道特定的调用目标并不那么容易。JVM可以动态加载新类,甚至可以在运行时重新定义现有类。在编译时看似非虚拟的公共方法可能在运行时变成虚拟的

您是对的,vtable查找可能会对性能产生影响。然而,
invokevirtual
字节码并不意味着vtable查找

例如,HotSpot JVM尽最大努力实现方法调用的设备化。它依靠类层次结构分析和运行时类型概要文件将
invokevirtual
转换为直接调用,或者更好的是,将“虚拟”方法直接内联到调用站点。只有真正的megamorphic调用站点(在运行时有3个或更多目标)进行vtable查找


也就是说,在现代JVM中,当目标方法实际上是非虚拟的时,
invokespecial
invokevirtual
之间没有性能差异。

作为补充,特别是在编译器可以正确推断公共目标方法的调用不能以不同的方式结束的情况下,也就是说,被重写的方法(问题是关于这些方法的),就像新操作的最终目标或直接结果一样,可以由JVM的优化器甚至链接器轻松识别,而无需使用专用指令(如
invokespecial
)标记这些调用。这甚至适用于
invokevirtual
的旧用例,例如,现在,同一嵌套组中的私有方法通过
invokevirtual
调用,并在运行时进行优化。