javac 生成一个桥接方法,其中包含指向抽象方法的 invokespecial 指令

标签 java jvm javacompiler jvm-bytecode

假设以下实际代码结构:

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/

相关文章:

java - 我们可以在硬件中实现一个本地执行 Java 字节码的 Java 解释器吗?

java - Activity 内的透明圆圈

java - 如何在Play 2.1中正确编写数据库集成测试?

java - JVM 会垃圾收集内存中的孤立周期吗?

java - Java 方法可以有超过 255 个局部变量吗?

Gradle增量java编译导致完全重新编译

java - 如何动态编译和运行资源中带有.class文件的.java文件?

java - java编译器如何检查接口(interface)中的所有方法是否都已实现?

java - 我可以在 JEditorPane 上方但 JTabbedPane 下方获取 JTextField 吗?

java - 使用处理程序更新 UI 线程