不同的Java编译器(供应商不同)会产生不同的字节码

时间:2013-11-28 12:16:41

标签: java compiler-construction javac bytecode

鉴于相同的主要版本,比如Java 7,做不同的Java编译器(例如,Oracle的热点,JRockit或IBM的J9等......)将给定的java源代码文件编译成相同的字节码?

扫描Java 7 language spec似乎正在讨论的是语言的语义,而不是将代码转换为字节码。

这个问题与不同的major.minor版本不同,给定供应商生成相同的字节码。这个问题已经回答here了 - 可能是

从以下answerIs the creation of Java class files deterministic?以及对this的答案的评论,以及上面1和{{{major}上的major.minor问题的两个答案。 3}},我认为我的问题的答案是

上述摘录如下:

  

JLS使许多实现细节不同于一个   实施到另一个。

  

但是,JLS没有指定从源代码到1的1:1映射   生成的字节码,所以你不应该依赖完全相同的字节   要生成的代码。

然而评论2暗示不同:

  

这是编译器,即javac,使用a创建代码   等等等等等等。这与HotSpot无关。

这意味着给定代码X所有javac实现(相同版本/不同供应商)必须生成相同的Y字节码。

我看不出那是怎么回事,但我无法证实它不是(或者我认为,见上文)是正确的。

可以给出明确的答案吗?

3 个答案:

答案 0 :(得分:2)

有两个问题:

  1. 不同的java编译器是否可以为相同的源代码生成不同的字节码?
  2. 他们是否真的为同一个源生成不同的字节码。
  3. 显然,1的答案是肯定的。否则,JLS必须完全指定为每个语言结构生成的字节码。但它没有。

    答案2我不确定,虽然我听说eclipse编译器在某些情况下生成的代码与javac略有不同。应该很容易验证。

答案 1 :(得分:2)

有问题的评论实际上并不反对。请注意,您在这里混合了两个不同的东西:Java字节码编译器(javac)和Java即时编译器(例如HotSpot或J9)。您通常使用一些javac实现将java源代码转换为java字节码。

然后你获取字节码并在JVM中执行它,它使用另一个编译器。

同样,有两组编译器:

  1. 字节码编译器(.java.class
  2. 即时编译器作为Java虚拟机的一部分(执行.class文件)
  3. 编辑:这些都不能保证产生相同的结果(即,相同的java文件可以产生不同的class文件,并且class相同当JIT完成后,文件可以产生不同的机器代码。))

    有两个顺序编译过程的原因是,如果将所有内容都包装到一个编译器中,则会丢失两个属性:

    1. 您编译的程序将是特定于平台的
    2. 您的程序不会(轻松)执行Java提供的一些优化和高级语言功能(反射,动态类加载)。

答案 2 :(得分:2)

编译器之间存在差异,有趣的是,一些允许的差异导致了过去的问题。

有些差异很小,例如一些编译器优化x=x+1以生成与x++相同的字节码,其他编译器则不生成。{/ p>

其他人可能会产生更大的影响,例如标准没有指定如何生成过去用于实现对私有成员(和类似事物)的内部类访问的合成成员的名称(我不知道它是否在今天)。但是,计算默认serialVersionUID的算法使用了所有类成员的哈希码,甚至是合成的。

因此,使用javac或第一个Eclipse版本进行编译会创建具有不兼容serialVersionUID的类。今天,Eclipse对合成成员使用与javac相同的名称模式,并默认发出serialVersionUID类中缺少显式Serializable的警告。

仍有很多自由,甚至用pack200打包,解包可能会创建具有与原始类不同的字节代码的类。