不同的Java编译器(供应商不同)会产生不同的字节码
给定相同的主要版本,比如Java 7,做不同的Java编译器(例如,Oracle的热点,JRockit或IBM的J9等……)将给定的java源代码文件编译成相同的bytcode?
扫描Java 7语言规范似乎正在讨论的是语言的语义,而不是将代码转换为字节码。
这个问题与不同的major.minor版本不同,给定供应商生成相同的字节码。 这个问题已在这里得到解答 – 可能是 。
从以下答案到Java类文件的创建是否确定? 并且对这个答案的评论引用了这个问题以及对于1和2上面的major.minor问题的两个答案,我认为我的问题的答案是肯定的 。
上述摘录如下:
JLS留下了许多实现细节,从一个实现到另一个实现。
和
但是,JLS没有指定从源代码到生成的字节代码的1:1映射,因此您不应该依赖于生成完全相同的字节代码。
然而, 这里的评论意味着不同:
它是编译器,即javac,使用BLAH BLAH BLAH创建代码。 这与HotSpot无关。
这意味着给定代码X所有javac实现(相同版本/不同供应商)必须生成相同的Y字节码。
我不明白这是怎么回事,但我无法证实它不是(或者我认为,见上文)是正确的。
能给出明确的答案吗?
编译器之间存在差异,有趣的是,一些允许的差异导致了过去的问题。
一些差异很小,例如,一些编译器优化x=x+1
以产生与x++
相同的字节码,而其他编译器则不然。
其他人可以产生更大的影响,例如标准没有指定如何生成过去用于实现对私有成员(和类似事物)的内部类访问的合成成员的名称(我不知道它是否在今天)。 但是用于计算默认serialVersionUID
的算法在所有类成员上使用哈希码,甚至是合成成员。
因此,使用javac
或第一个Eclipse版本进行编译会创建具有不兼容的serialVersionUID
的类。 今天,Eclipse对合成成员使用与javac
相同的名称模式,并在默认情况下发出有关在Serializable
类中缺少显式serialVersionUID
的警告。
仍然有很多自由,甚至包装pack200
包可能会创建具有不同于原始类的字节代码的类。
有两个问题:
- 不同的java编译器是否可以为相同的源代码生成不同的字节码?
- 它们实际上是否为同一源生成不同的字节码。
显然,1的答案是肯定的。 否则,JLS必须完全指定为每个语言结构生成的字节码。 但事实并非如此。
答案2我不确定,虽然我听说eclipse编译器在某些情况下产生的代码与javac略有不同。 应该很容易validation。
有问题的评论实际上并不反对。 请注意,您在这里混合了两个不同的东西:Java字节码编译器( javac
)和Java即时编译器(例如HotSpot或J9)。 您通常使用一些javac实现将java源代码转换为java字节码。
然后你获取字节码并在JVM中执行它,它使用另一个编译器。
同样,有两组编译器:
- 字节码编译器(
.java
到.class
) - 即时编译器作为Java虚拟机的一部分(执行
.class
文件)
( 编辑:这些都不能保证产生相同的结果(即,相同的java
文件可以产生不同的class
文件,并且当JIT完成时,相同的class
文件可以产生不同的机器代码。))
有两个顺序编译过程的原因是,如果将所有内容都包装到一个编译器中,则会丢失两个属性:
- 您编译的程序将是特定于平台的
- 您的程序不会(轻松地)执行Java提供的一些优化和高级语言function(reflection,动态类加载)。