Compiler construction 不同的JDK更新是否会产生不同的Java字节码?

Compiler construction 不同的JDK更新是否会产生不同的Java字节码?,compiler-construction,compilation,java,Compiler Construction,Compilation,Java,假设情况: 我有一个项目,其源代码符合性级别被指定为1.5。 现在我使用两种不同的JDK编译这个项目:首先使用JDK 6 Update 7,然后使用JDK 6 Update 20 这两个不同的JDK是否产生不同的Java字节码,尽管它们只在更新版本上有所不同?生成的代码通常只在编译器错误修复时不同 然而,JLS没有指定从源代码到生成的字节码的1:1映射,因此您不应该依赖于要生成的完全相同的字节码。如果至少在某些情况下没有导致字节码发生更改,那么为什么有人会麻烦地发布开发工具包的更新?我强烈怀疑是

假设情况:

我有一个项目,其源代码符合性级别被指定为1.5。 现在我使用两种不同的JDK编译这个项目:首先使用JDK 6 Update 7,然后使用JDK 6 Update 20


这两个不同的JDK是否产生不同的Java字节码,尽管它们只在更新版本上有所不同?

生成的代码通常只在编译器错误修复时不同


然而,JLS没有指定从源代码到生成的字节码的1:1映射,因此您不应该依赖于要生成的完全相同的字节码。

如果至少在某些情况下没有导致字节码发生更改,那么为什么有人会麻烦地发布开发工具包的更新?我强烈怀疑是否有人会仅仅为了文档更新而这样做。

让我们从另一个角度回答这个问题:不能保证任何两个版本的jdk都会产生相同的字节码。因此,您可以预期总体上的差异。

只要符合JLS中指定的行为,就没有任何东西可以阻止不同版本生成不同的字节码。JLS的许多实现细节因实现的不同而有所不同。

字节码可能略有不同,但这没什么好担心的,因为它仍然是兼容的


真正执行的内容取决于JIT。

与通常针对不同编译器的情况一样,Java情况下也是如此:结果必须相同,但实现方式可能不同(从字节码的角度来看),例如,由于优化或类似的原因。JVM是基于堆栈的V机;下面是一个虚构的示例(我不知道操作码指令的jvm助记符)

推10 推20 添加 推19 推1 添加 推10 添加
它们产生相同的结果,但生成的字节码不同(第一个稍微优化,第二个“完全”未优化;第三个选项可能是
push 30
,因为我们正在添加已知(可能在编译时)常量)。这是一个简单的例子,但更复杂的例子很容易构建。

例如JDK 6 Update 7的编译器可能输出的字节码与JDK 6 Update 20的编译器略有不同,但由于它都是Java 6,类文件将完全兼容-您将能够在更新7上运行使用更新20编译的代码,而不会出现任何问题

在主要的Java版本之间(例如Java5和Java6),可能会有更改,以便在较新版本上编译的代码不会在较旧版本上运行。例如,对于Java7,最有可能出现一条新指令。包含该指令的类文件将无法在较旧的Java版本上运行


但是,在更新版本之间永远不会进行如此大的更改。

如果使用不同的JDK版本编译,我建议使用javac的target选项。 否则,您可能无法使用较旧的JDK运行jar


您可能还希望使用javac的source选项,以确保开发人员不会使用最近的JDK中添加的类/方法。

回答您的反问:因为字节码的解释/执行以及库可能已经更改。更新之间对JDK的大多数更改都是对运行时和库的更改,而不是对编译器的更改.@polygenelooders:binary兼容性是指在保持类文件与其他未重新编译的类文件兼容的同时,允许对源代码进行更改。这是一个有用的话题,但不要认为它适用于这个问题。 push 10 push 20 add push 19 push 1 add push 10 add