[英]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
的文档没有说明应该为接口方法使用不同的查找算法,这意味着通常不可能调用interface
的static
方法。
这显然不是规范的意图,它在interface
s中包含static
方法的明确添加的特性,当然也应该是可调用的。
在您的示例中,调用类确实违反了规范,即§4.4.2 ,因为它在声明类更改后通过CONSTANT_Methodref_info
而不是CONSTANT_InterfaceMethodref_info
引用接口方法。 但是, invokestatic
指令文档的当前状态并没有invokestatic
要求根据常量池项的类型更改行为(可能是实际意图,但它不存在)。 并且, invokestatic
,坚持当前的措辞意味着拒绝interface
上的任何invokestatic
。
因此规范需要另一次清理,但是由于Methodref_info
和InterfaceMethodref_info
之间的区别远远没有Java 8之前那么有用(与上面链接的答案相比),如果最终修复转向,我不会感到惊讶将来完全消除这种区别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.