为什么 Java 编译器 11 使用 invokevirtual 来调用私有方法?
当使用 OpenJDK 8 中的 Java 编译器编译以下代码时,对 的调用是通过 一个 来完成的,但是当使用 OpenJDK 11 时,将发出 一个。foo()
invokespecial
invokevirtual
public class Invoke {
public void call() {
foo();
}
private void foo() {}
}
使用 1.8.0_282 时的输出:javap -v -p
javac
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
使用 11.0.10 时的输出:javap -v -p
javac
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()
在挖掘了一下之后,似乎 on 私有方法的目的是允许嵌套类从外部类调用私有方法。所以我尝试了下面的代码:invokevirtual
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
invokevirtual
foo()
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
所有这些都有点令人困惑,并提出了一些问题:
- 为什么用于调用私有方法?有没有一个用例,用 代替它不等于?
invokevirtual
invokespecial
- 调用 in 如何不从中选取方法,因为它是通过 调用的?
getValue()
Nested.getValueInNested()
Derived
invokevirtual