问题
As anyone who can answer this question will already know, the JVM supports several bytecode instructions for invoking methods (invokevirtual
, invokespecial
, invokestatic
, ...)
Most method calls on instance methods are made by invokevirtual
, but private methods and initializer methods are called via invokespecial
, as described in the JVM spec:
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.
As I understand it, invokevirtual
performs a vtable lookup to resolve the method while invokespecial
, since the correct method implementation is known at link time, is resolved statically.
My question is, why is invokespecial
not used to call public
methods in cases where the concrete class of the method owner is known at compile-time? It seems to me that avoiding a vtable lookup would be desirable for efficiency reasons. But obviously there is something that I don't understand about the JVM.
回答1:
First, it's not that easy to know the particular call target at compile time. JVM can load new classes dynamically and can even redefine the existing classes in runtime. A public method that appeared non-virtual at compile time may happen to become virtual in runtime.
You are right that vtable lookup can have a performance impact. However, invokevirtual
bytecode does not imply vtable lookup at all.
For example, HotSpot JVM does its best to devirtualize method calls. It relies on Class Hierarchy Analysis and Runtime Type Profiles to translate invokevirtual
to direct calls or, even better, to inline "virtual" methods directly into the call site. Only true megamorphic call sites (that have 3 or more targets in runtime) undergo a vtable lookup.
That said, with modern JVMs there is no performance difference between invokespecial
and invokevirtual
when the target method is actually non-virtual.
来源:https://stackoverflow.com/questions/58237483/invoking-public-methods-with-invokespecial