Java二进制兼容性发生了什么?

20

我偶然发现了一组旧的课程,日期为1997年3月。那时我尝试学习Java,使用的是JDK 1.0.2。

有趣的是,我保存了源文件和类文件,它们至今仍可以被编译和执行,这真的很酷。但是Java不应该保持二进制兼容性吗?在某个地方,这种格式不再有效了。Java 8虚拟机将会报告;

Exception in thread "main" java.lang.ClassFormatError: Invalid start_pc 65535 in LocalVariableTable in class file bali/core/Application
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    :
    [snip many ClassLoader calls]
    :
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

有问题的类是我从命令行调用的类的超类。

还有一个细节,在那些日子里,微软仍然在Java阵营中,我记得他们的javac更符合不良语法。Sun编译器很乐意接受“public synchronized class Abc”和许多其他无效语句。因此,这些类文件很可能是由MS编译器生成的,然后在Sun JVM上运行。

无论如何,我的问题是:是否有人了解早期Java版本中的兼容性承诺?这是一件大事,还是有意放弃?或者是在更晚的版本,比如Java 1.4或Java 5中做出的决定,简单地放弃了JDK 1.0支持?


1
我在网上找到了一些评论,表明旧版的javac存在问题,生成错误的字节码,而后续版本的验证器可以捕获其中的一些错误。特别是在Java 6中发生了一项变化,可能开始捕获这些错误。 - Niclas Hedhman
6
该类文件无效。Java 二进制兼容性仅适用于有效的类文件。早期 JVM 可能会宽松些,但这并不会改变现状。 - Andreas
在软件开发中,是否修复某个 bug 会破坏之前做出的兼容性承诺,这常常是一个难以抉择的问题。但是,在这种情况下,所涉及的 bug 可能非常严重,因此打破兼容性也是值得的。 - biziclop
你能使用 javap 反汇编这个类吗? - biziclop
1个回答

4
正如你所提到的,问题很可能是由于编译器从Microsoft编译器切换到Sun编译器时引入的。Sun表示,Microsoft编译器生成的类文件不遵循Java规范,因此无效。
你可以在这里找到更多细节here

这个错误是由旧的JDK 1.0.2或1.1编译器生成的字节码引起的。过去,许多这些编译器生成了不符合Java VM规范的字节码。由于最近的J2SE版本中的验证器对于坏的类格式更加严格,当加载这些坏的类文件时,VM会抛出ClassFormatError。

关于一般问题,Java仍然坚定地致力于向后兼容,并且从未发生过重大突破。每个版本通常都会在边缘问题上有轻微的变化。我不知道有没有主表,但这里有各个版本的表:
  • Java 8 (与Java 7完全二进制兼容)
  • Java 7 (与Java 6大部分二进制兼容)
  • Java 6 (与Java 5大部分二进制兼容,加上一个注释:一些混淆器生成的类文件不在规范范围内,因此这些类文件可能无法运行)
  • Java 5 (与Java 1.4.2大部分二进制兼容,同样有关于混淆器的注释)
  • Java 1.0 - 1.4.2 (与之前版本大部分二进制兼容,有一些关于向前兼容性的注释,但未经测试)

非常感谢您提供的出色答案。 - Niclas Hedhman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接