继承的类不能覆盖java中的最后方法。
但是为什么最后的方法是使用invokevirtual而不是invokespecial调用的。
发布于 2018-04-04 07:55:34
final修饰符的语义仅由字节码编译器强制执行。
invokespecial和invokevirtual之间的区别在于,invokevirtual基于对象的类调用一个方法。调用特殊指令用于调用当前类的超类的实例初始化方法以及私有方法和方法。
当我们调用最终方法时,相应的字节码指令是INVOKEVIRTUAL,与其他非最终方法一样。
下面是使用final关键字调用方法的示例。
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
// 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
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;
}
}发布于 2022-08-13 05:19:58
听起来你实际上想问的是:
为什么我们需要一个可静态链接的方法的vtable查找?
请放心,在实践中,这种查找是在链接- 至少在HotSpot里期间优化的。
事实上,最终实例方法被看作是虚拟的,而不是特殊的,这似乎是JVMS的一个技术性问题。
发布于 2022-08-13 05:56:23
为了在INVOKEVIRTUAL中实现二进制兼容性规则,有必要使用final方法调用JLS 13.4.17方法。
“将声明为
final的方法更改为不再声明为final并不会破坏与现有二进制文件的兼容性。”
如果将对final方法的调用编译为INVOKESPECIAL,那么如果方法被更改为非final,则需要重新编译。这违反了上面的规则。
但是,正如其他答案/注释已经指出的那样,JIT编译器无论如何都会选择最佳的调用序列。即使没有将方法声明为final,JIT编译器也可以确定何时不需要vtable调度。(它甚至可以在加载使先决条件无效的新类时重新编译方法。)
https://stackoverflow.com/questions/49633525
复制相似问题