使用 invokespecial 调用 public 方法?

Invoking public methods with invokespecial?

任何能回答这个问题的人都知道,JVM 支持几种用于调用方法的字节码指令(invokevirtualinvokespecialinvokestatic、...)

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

The difference between the invokespecial and the invokevirtual instructions is that invokevirtual invokes a method based on the class of the object. The invokespecial instruction is used to invoke instance initialization methods as well as private methods and methods of a superclass of the current class.

据我了解,invokevirtual 执行 vtable 查找来解析该方法,而 invokespecial,因为在 link 时已知正确的方法实现,静态解析。

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

首先,要在编译时知道特定的调用目标并不容易。 JVM 可以动态加载新的 类,甚至可以在运行时重新定义现有的 类。 public 在编译时显示为非虚拟的方法可能在运行时恰好变为虚拟。

你说得对,vtable 查找会对性能产生影响。但是,invokevirtual 字节码根本不暗示 vtable 查找。

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

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