Сер*_*еев 5 java jvm language-specifications binary-compatibility
我遇到了以下奇怪的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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后重新编译Class to be an interface without recompiling theUser`:
public interface Class {
public static void foo() {
System.out.println("hi");
}
}
Run Code Online (Sandbox Code Playgroud)
运行User.mainnow会产生相同的输出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
Run Code Online (Sandbox Code Playgroud)
所以我们这里有一个叫做CONSTANT_Methodref_infoclasspool的东西.
让我们引用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章中将类更改为接口的二进制兼容性的提及.二进制兼容性.此外,没有任何关于引用相同静态方法的棘手案例的说法.
任何人都可以详细说明并告诉我,如果我错过了什么?
首先,由于您的示例不包含继承,因此我们不需要 xe2x80x99t 假设我们没有 Classxe2x80x9d 的继承者,只需没有。因此 \xc2\xa75.3.5 的引用部分与此示例无关。
\n\n\xc2\xa76.5 的引用部分,命名 \xe2\x80\x9c对方法或接口方法\xe2\x80\x9d 的符号引用,具有讽刺意味的是,Java\xc2\xa08 进行了更改以放宽限制。该invokestatic指令明确允许在接口方法上调用,如果它们是static指令。
您在最后引用的第一个项目符号\xc2\xa75.4.3.3interface指出,如果声明类型是 an ,方法解析应该无条件失败,确实违反了,但无论如何它都没有意义。由于 it\xe2\x80\x99s 无条件引用,即invokestaticdoes\xe2\x80\x99t 的文档声明接口方法应使用不同的查找算法,这意味着static调用interface通常是不可能的。
\xe2\x80\x99s 显然不是规范的意图,它包含了static方法中显式添加的功能interface的特性,当然这些方法也应该是可调用的。
在您的示例中,调用类确实违反了规范,即\xc2\xa74.4.2 ,因为它在声明类更改后引用接口方法 viaCONSTANT_Methodref_info而不是。CONSTANT_InterfaceMethodref_info但是指令\xe2\x80\x99s文档的当前状态invokestatic并不\xe2\x80\x99s强制要求根据常量池项\xe2\x80\x99s类型更改行为(这可能是实际意图,但它\ xe2\x80\x99s 不存在)。而且,如前所述,遵守当前的措辞将意味着拒绝任何invokestatic关于interface.
因此,规范需要另一次清理,但由于Methodref_info和之间的区别InterfaceMethodref_info到目前为止不如 Java\xc2\xa08 之前那么有用(与上面链接的答案相比),我不会\xe2\x80\x99 感到惊讶,如果最终的解决办法是在未来完全消除这种区别。
| 归档时间: |
|
| 查看次数: |
372 次 |
| 最近记录: |