假设以下现实代码结构:
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:
如果满足以下所有条件,则让C为当前类的直接超类。
因此,在我们的例子中,A将被选为C.
通过以下查找过程选择要调用的实际方法。
1)如果C包含一个与解析方法具有相同名称和描述符的实例方法的声明,那么它就是要调用的方法。
因此JVM将选择A.m()。
但运行时异常部分指出:
否则,如果查找过程的步骤1,步骤2或步骤3选择抽象方法,则invokespecial将抛出AbstractMethodError。
因此调用该方法将导致错误。
我只是想知道,为什么Java编译器生成这样的判断失败字节码?
P.S。我猜想上面的桥接方法永远不会被调用,因为类A.B的最终实现者会覆盖它。但随后会出现以下问题:java生成此桥接方法的目的是什么?
答案 0 :(得分:0)
我真的不明白你想要达到的目标。您想了解为什么生成该方法?
注意使用指向抽象的invokespecial指令 方法A.m()。在我看来,这必然导致AbstractMethodError 在运行时
理论上应该没有抽象类的实例,任何实例化的子类都必须实现所有抽象方法。所以 invokespecial 指向实现子类。尝试实例化抽象类通常由编译器捕获。
当没有找到实现子类时抛出AbstractMethodError,大部分时间是在按预期加载不同的类版本或使用字节码操作时发生的。