[英]Why final methods in java are invoked using invokevirtual opcode
Final methods in java cannot be overridden by the inherited class. java 中的最终方法不能被继承的 class 覆盖。
But why the final methods are invoked using invokevirtual
instead of invokespecial
.但是为什么使用
invokevirtual
而不是invokespecial
来调用最终方法。
The semantics of the final
modifier are only enforced by the bytecode compiler . final
修饰符的语义仅由字节码编译器强制执行。
The link to JavaSE7 specification Some other samples about final
keyword. JavaSE7规范的链接 关于
final
关键字的一些其他示例。
The difference between the invokespecial and the invokevirtual instructions is that invokevirtual invokes a method based on the class of the object.
invokespecial和invokevirtual指令之间的区别在于invokevirtual基于对象的类调用方法。 The invokespecial instruction is used to invoke instance initialization methods as well as private methods and methods of a superclass of the current class.
invokespecial指令用于调用实例初始化方法以及当前类的超类的私有方法和方法。
When we invoke a final method, corresponding bytecode instruction is INVOKEVIRTUAL
, the same as other non-final method. 当我们调用final方法时,相应的字节码指令是
INVOKEVIRTUAL
,与其他非final方法相同。
final
keyword. final
关键字调用方法的示例。 CounterPoint.java CounterPoint.java
public class CounterPoint extends Point {
private static final AtomicInteger counter = new AtomicInteger();
public CounterPoint(int x, int y) {
super(x, y);
counter.incrementAndGet();
}
public static String numberCreated() {
return counter.toString();
}
}
ByteCode of CounterPoint CounterPoint的ByteCode
// class version 52.0 (52)
// access flags 0x21
public class com/xetrasu/CounterPoint extends java/awt/Point {
// compiled from: CounterPoint.java
// access flags 0x1A
private final static Ljava/util/concurrent/atomic/AtomicInteger; counter
// access flags 0x1
public <init>(II)V
L0
LINENUMBER 11 L0
ALOAD 0
ILOAD 1
ILOAD 2
INVOKESPECIAL java/awt/Point.<init> (II)V
L1
LINENUMBER 12 L1
GETSTATIC com/xetrasu/CounterPoint.counter : Ljava/util/concurrent/atomic/AtomicInteger;
INVOKEVIRTUAL java/util/concurrent/atomic/AtomicInteger.incrementAndGet ()I
POP
L2
LINENUMBER 13 L2
RETURN
L3
LOCALVARIABLE this Lcom/xetrasu/CounterPoint; L0 L3 0
LOCALVARIABLE x I L0 L3 1
LOCALVARIABLE y I L0 L3 2
MAXSTACK = 3
MAXLOCALS = 3
// access flags 0x9
public static numberCreated()Ljava/lang/String;
L0
LINENUMBER 16 L0
GETSTATIC com/xetrasu/CounterPoint.counter : Ljava/util/concurrent/atomic/AtomicInteger;
INVOKEVIRTUAL java/util/concurrent/atomic/AtomicInteger.toString ()Ljava/lang/String;
ARETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 8 L0
NEW java/util/concurrent/atomic/AtomicInteger
DUP
INVOKESPECIAL java/util/concurrent/atomic/AtomicInteger.<init> ()V
PUTSTATIC com/xetrasu/CounterPoint.counter : Ljava/util/concurrent/atomic/AtomicInteger;
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
AtomicInteger.java AtomicInteger.java
public class AtomicInteger extends Number implements java.io.Serializable {
public String toString() {
return Integer.toString(get());
}
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
}
Sounds like what you're actually asking is:听起来您实际上要问的是:
Why would we need a vtable lookup for a method that could be linked statically?
为什么我们需要对可以静态链接的方法进行vtable查找?
And rest assured, in practice this lookup is optimized away during linkage - at least in HotSpot .并且 rest 保证,在实践中,这种查找在链接期间被优化 - 至少在 HotSpot 中。
The fact final instance methods are treated as virtual rather than special seems like a technicality of the JVMS.最终实例方法被视为虚拟而不是特殊的事实似乎是 JVMS 的技术性问题。
It is necessary to use INVOKEVIRTUAL
to call a final
method in order to implement the binary compatibility rule in JLS 13.4.17 .为了实现JLS 13.4.17中的二进制兼容性规则,需要使用
INVOKEVIRTUAL
调用final
方法。
"Changing a method that is declared
final
to no longer be declaredfinal
does not break compatibility with pre-existing binaries. "“将声明为
final
的方法更改为不再声明为final
不会破坏与预先存在的二进制文件的兼容性。”
If calls to final
method were compiled to INVOKESPECIAL
, then those calls would need to be recompiled if the method was changed to not be final
.如果对
final
方法的调用编译为INVOKESPECIAL
,那么如果方法更改为非final
,则需要重新编译这些调用。 That violates the rule above.这违反了上面的规则。
But as the other answers / comments have already noted, the JIT compiler will choose the best calling sequence anyway.但正如其他答案/评论已经指出的那样,JIT 编译器无论如何都会选择最佳调用序列。 Even if you don't declare a method as
final
, the JIT compiler can figure out when no vtable dispatching is necessary.即使您没有将方法声明为
final
,JIT 编译器也可以确定何时不需要 vtable 调度。 (And it can even recompile methods when a new class is loaded that invalidates the preconditions.) (它甚至可以在加载新的 class 使前提条件无效时重新编译方法。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.