当使用 OpenJDK 8 中的 Java 编译器编译以下代码时,调用foo()
是通过一个完成的invokespecial
,但是当使用 OpenJDK 11 时,invokevirtual
被发射。
public class Invoke {
public void call() {
foo();
}
private void foo() {}
}
输出javap -v -p
when javac
使用1.8.0_282:
public void call();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #2 // Method foo:()V
4: return
输出javap -v -p
when javac
使用 11.0.10:
public void call();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokevirtual #2 // Method foo:()V
4: return
我不明白为什么invokevirtual
此处使用,因为无法覆盖foo()
.
经过一番挖掘后,似乎目的是invokevirtual
on private method是允许嵌套类从外部类调用私有方法。所以我尝试了下面的代码:
public class Test{
public static void main(String[] args) {
// Build a Derived such that Derived.getValue()
// somewhat "exists".
System.out.println(new Derived().foo());
}
public static class Base {
public int foo() {
return getValue() + new Nested().getValueInNested();
}
private int getValue() {
return 24;
}
private class Nested {
public int getValueInNested() {
// This is getValue() from Base, but would
// invokevirtual call the version from Derived?
return getValue();
}
}
}
public static class Derived extends Base {
// Let's redefine getValue() to see if it is picked by the
// invokevirtual from getValueInNested().
private int getValue() {
return 100;
}
}
}
用 11 编译这段代码,我们可以在输出中看到javap
that invokevirtual
都用于foo()
and in getValueInNested()
:
public int foo();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
0: aload_0
// ** HERE **
1: invokevirtual #2 // Method getValue:()I
4: new #3 // class Test$Base$Nested
7: dup
8: aload_0
9: invokespecial #4 // Method Test$Base$Nested."<init>":(LTest$Base;)V
12: invokevirtual #5 // Method Test$Base$Nested.getValueInNested:()I
15: iadd
16: ireturn
public int getValueInNested();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #1 // Field this$0:LTest$Base;
// ** HERE **
4: invokevirtual #3 // Method Test$Base.getValue:()I
7: ireturn
所有这些都有点令人困惑并提出了一些问题:
- Why
invokevirtual
是用来调用私有方法的?是否有一个用例将其替换为invokespecial
不会是等价的吗?
- 如何调用
getValue()
in Nested.getValueInNested()
不选择方法Derived
因为它被称为通过invokevirtual
?