繁体   English   中英

使用静态方法将类更改为Java中的接口的二进制兼容性

[英]Binary compatibility of changing a class with static methods to interface in Java

我遇到了以下奇怪的Java / JVM规范不完整的情况。 假设我们有类(我们将使用Java 1.8和HotSpot):

public class Class {
  public static void foo() {
    System.out.println("hi");
  }
}

public class User {
  public static void main(String[] args) {
    Class.foo();
  }
}

然后重新编译Class to be an interface without recompiling the User`:

public interface Class {
  public static void foo() {
    System.out.println("hi");
  }
}

运行User.main现在产生相同的输出hi 这似乎是显而易见的,但我希望它会因IncompatibleClassChangeError而失败,这就是原因:

我知道根据JVM 5.3.5#3语句将类更改为接口是二进制不兼容:

如果命名为C的直接超类的类或接口实际上是一个接口,则加载会抛出IncompatibleClassChangeError

但是我们假设我们没有Class继承者。 我们现在必须参考JVM规范来了解方法的分辨率。 第一个版本被编译成这个字节码:

public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method examples/Class.foo:()V
       3: return

所以我们在这里有一个叫做类池中的CONSTANT_Methodref_info的东西。

让我们引用invokestatic的动作。

...该索引处的运行时常量池项必须是对方法接口方法 (第5.1节)的符号引用,它提供方法的名称和描述符(第4.3.3节)以及符号引用要在其中找到方法的类或接口。 解决指定的方法(第5.4.3.3节)

因此JVM以不同的方式处理方法和接口方法。 在我们的例子中,JVM将该方法视为类的方法(而不是接口)。 JVM尝试相应地解决它5.4.3.3方法解析:

根据JVM规范,JVM必须在以下语句中失败:

1)如果C是接口,则方法解析会抛出IncompatibleClassChangeError。

...因为Class实际上不是一个类,而是一个接口。

不幸的是,我没有找到任何关于在Java语言规范第13章中将类更改为接口的二进制兼容性的提及。二进制兼容性。 此外,没有任何关于引用相同静态方法的棘手案例的说法。

任何人都可以详细说明并告诉我,如果我错过了什么?

首先,由于您的示例不包含继承,因此我们不必“假设我们没有类的继承者”,根本就没有。 因此,§5.3.5中引用的部分与此示例无关。

引用的§6.5部分,命名为“ 对方法或接口方法的符号引用 ”具有讽刺意味的是,Java 8放宽了限制 如果接口方法是static ,则显式允许在接口方法上调用invokestatic指令。

§5.4.3.3的第一个项目,你在最后提到,指出方法解决方案应该无条件地失败,如果声明类型是一个interface ,确实被违反了,但无论如何它都没有意义。 由于它是无条件引用的,即invokestatic的文档没有说明应该为接口方法使用不同的查找算法,这意味着通常不可能调用interfacestatic方法。

这显然不是规范的意图,它在interface s中包含static方法的明确添加的特性,当然也应该是可调用的。

在您的示例中,调用类确实违反了规范,即§4.4.2 ,因为它在声明类更改后通过CONSTANT_Methodref_info而不是CONSTANT_InterfaceMethodref_info引用接口方法。 但是, invokestatic指令文档的当前状态并没有invokestatic要求根据常量池项的类型更改行为(可能是实际意图,但它不存在)。 并且, invokestatic ,坚持当前的措辞意味着拒绝interface上的任何invokestatic

因此规范需要另一次清理,但是由于Methodref_infoInterfaceMethodref_info之间的区别远远没有Java 8之前那么有用(与上面链接的答案相比),如果最终修复转向,我不会感到惊讶将来完全消除这种区别。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM