我最近看到一种让我在SO上问这个问题的行为。我希望人们也能分享他们的发现。
如果使用JDK 1.8 u66和JDK 1.8 u121编译(未更改)相同的文件,则类文件(字节码)会不同吗?我的意思是:
1)我使用JDK 1.8 u66编译应用程序 2)我对1或2个文件进行了更改,并使用JDK 1.8 u66重新编译。
我是否可以期待一些未更改的类文件具有不同的二进制内容,即使它们没有更改?
我的理由是,当我把一个文件的哈希值作为我上面步骤的一部分没有改变时 - 它们在磁盘上的大小相同,但哈希码完全不同。我使用Winmerge比较这两个版本,其中大小报告相同,但二进制内容不同。以下是我使用Winmerge进行比较的结果(蓝色标记的项目与我的源名称相关,因此我不得不掩盖它) - 但请注意208和248中的区别。
这是预期的吗?如果有的话,有人可以请我指出解释这个问题的文献吗?
此致
答案 0 :(得分:5)
存在无数的原因,为什么同一Java源文件可能被不同的编译器编译成不同的字节,同一编译器的不同版本应该被视为不同的编译器。即使对于完全相同的编译器,也不能保证字节是相同的。
一个这样的原因是,代码中的所有引用(除了操作码和字节码偏移之外)都是通过Constant Pool间接的。未指定常量池中条目的顺序,因此它可能会更改,从而导致使用不同偏移的所有引用。
另请参阅JVMS有一个标题为Compiling for the Java Virtual Machine的部分,然而,该部分首先说:
本章中编号的部分不是规范性的
因此,推理仅在一个方向上起作用:相同的字节意味着相同的源代码,但不同的字节并不一定意味着不同的源代码。
从一个注释链接的JDK-8067422给出了一个示例,即使相同的编译器也可以为同一源文件生成不同的字节(可能是由于在同一编译器调用中编译的不同源文件集)。根据JLS和JVMS,这是 legal ,只是不方便。