java 字节码总是向前兼容吗?

Is java byte-code always forward compatible?

我了解由版本 JDK X 生成的字节码保证可以在 JVM Y 上运行,前提是 Y >= X。

这是否适用于 JDK/JVM 的所有版本? 即期望 JDK 1 生成的 class 文件在 JVM 11 上工作是否公平?

参考JVM specs, JDK 8 compatibility guide and Java 11 JSR 在那里找不到准确的答案。

字节码本身应该可以在未来的版本中使用。直到现在这都是正确的,但没有人知道这是否适用于所有未来。

API 中的更改是什么更改,并且可能会破坏您的程序。已弃用的 API 可能会在未来消失,然后您的程序将不再工作,并且在引用此类方法时可能会抛出 java.lang.NoSuchMethodError

Java 字节码不向前兼容,JVM 向后兼容。这些属性之间的区别在于,任何未来的 JVM 都可能决定放弃对某个较旧字节代码版本的向后兼容性。

Java 字节码的设计方式很少需要这种削减,但已经有意限制向后兼容性。从 Java 8 开始,对 Java 1.0 的 invokespecial 不同语义的支持已被删除。正如 JVM Spec §4.1 所述:

The ACC_SUPER flag indicates which of two alternative semantics is to be expressed by the invokespecial instruction (§invokespecial) if it appears in this class or interface. Compilers to the instruction set of the Java Virtual Machine should set the ACC_SUPER flag. In Java SE 8 and above, the Java Virtual Machine considers the ACC_SUPER flag to be set in every class file, regardless of the actual value of the flag in the class file and the version of the class file.

The ACC_SUPER flag exists for backward compatibility with code compiled by older compilers for the Java programming language. In JDK releases prior to 1.0.2, the compiler generated access_flags in which the flag now representing ACC_SUPER had no assigned meaning, and Oracle's Java Virtual Machine implementation ignored the flag if it was set.

这并不意味着早期的 Java 1.0 代码通常不起作用。只有依赖于早期版本 invokespecial 过时且现在不受支持的语义的代码才会中断。

另一项更改是 jsrret 指令已被删除¹,但是,此更改已与较新的 class 文件版本相关联,因此这些指令仍受支持较旧的 class 文件版本,因此它不会破坏现有代码。但这可能是未来 JVM 放弃对这些旧版本支持的原因。


¹ JVM spec §4.9.1:

If the class file version number is 51.0 or above, then neither the jsr opcode or the jsr_w opcode may appear in the code array.

没有提到ret指令,但没有jsr指令就不起作用。