假设以下实际代码结构:
interface I {
I m();
}
abstract class A implements I {
@Override
public abstract A m();
abstract class B extends A {
}
}
为B生成的字节码是
abstract class A$B extends A {
<some stuff>
public I m(); //bridge method
Code:
0: aload_0
1: invokespecial #2 // Method A.m:()LA;
4: areturn
}
注意指向抽象方法A.m()的invokespecial指令的使用。在我看来,根据 invokespecial 上的 JVM 8 规范,这一定会在运行时导致 AbstractMethodError 。 :
If all of the following are true, let C be the direct superclass of the current class.
因此,在我们的示例中,A 将被选为 C。
The actual method to be invoked is selected by the following lookup procedure.
1) If C contains a declaration for an instance method with the same name and descriptor as the resolved method, then it is the method to be invoked.
所以JVM会选择A.m()。
但是运行时异常部分指出:
Otherwise, if step 1, step 2, or step 3 of the lookup procedure selects an abstract method, invokespecial throws an AbstractMethodError.
因此调用该方法将以错误结束。
我只是想知道,为什么Java编译器会生成这样的被判失败的字节码?
附注我猜测上述桥接方法根本不会被调用,因为 A.B 类的最终实现者将覆盖它。但随之而来的问题就出现了:java生成这个桥接方法的目的是为了什么?
最佳答案
我不太明白你想达到什么目的。您想了解为什么会生成该方法吗?
Notice the use of invokespecial instruction pointing to the abstract method A.m(). In my opinion this must lead to an AbstractMethodError at runtime
理论上不应该存在抽象类的实例,任何实例化的子类都必须实现所有抽象方法。所以invokespecial指向实现子类。尝试实例化抽象类通常会被编译器捕获。
当没有找到实现子类时会抛出AbstractMethodError,大多数情况下,当按预期加载不同的类版本或使用字节码操作时,会发生这种情况。
关于javac 生成一个桥接方法,其中包含指向抽象方法的 invokespecial 指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42566298/