相同的Java源代码编译为二进制不同的类

Vic*_*cki 11 java compilation

任何人都可以解释相同的Java源代码如何最终编译为二进制不同的类文件?

问题来自以下情况:

我们有一个相当大的应用程序(800多个类)已经分支,重组然后重新集成回主干.在重新集成之前,我们将主干合并到分支中,这是标准过程.

最终结果是一组带有分支源的目录和一组带有主干源的目录.使用Beyond Compare,我们能够确定两组源相同.但是,在编译时(使用IntelliJ v11中托管的maven的相同JDK),我们注意到大约十几个类文件是不同的.

当我们为每对明显不同的类文件反编译源代码时,我们最终得到了相同的java源代码,因此就最终结果而言,它似乎并不重要.但为什么只有少数文件不同?

谢谢.


额外的想法:

如果maven/javac以不同的顺序编译文件,可能会影响最终结果吗?

Ste*_*n C 7

假设JDK版本,构建工具版本和构建/编译选项相同,我仍然可以想到5种可能的差异来源:

  1. 时间戳-类文件可以1包含编译时间戳.除非您在完全相同的时间运行编译,否则同一文件的不同编译将导致不同的时间戳.

  2. 源文件名路径 - 每个类文件包含源文件的路径名.如果编译具有不同路径名的两个树,则类文件将包含不同的源路径名.

  3. 导入的编译时常量的值 - 当类A使用在另一个类中定义的编译时常量时B(请参阅JLS以定义"编译时常量"),常量的值将合并到As类文件中.因此,如果A针对不同版本B(对于常量使用不同的值)进行编译,则代码A可能会有所不同.

  4. 外部类/方法签名的差异; 例如,如果您在其中一个POM文件中更改了依赖项版本.

  5. 构建类路径中的差异可能导致导入类的顺序不同,这可能导致类文件的常量池中条目顺序的非显着差异.这可能是由于以下因素:

    • 在外部JAR文件的目录中以不同顺序出现的文件,
    • 由于源文件在构建工具迭代时的顺序不同,文件按不同顺序编译,或者
    • 构建中的并行性(如果已启用).

请注意,您通常不会看到FS目录中的文件的实际顺序,因为类似的工具lsdir默认显示在他们面前排序项.

1 - 这取决于编译器.此外,无法保证javap将显示时间戳...如果它们存在.


我应该补充一点,确定差异原因的第一步是弄清楚它们究竟是什么.你可能需要(需要)以这种方式做到这一点 - 通过手动解码一对类文件来识别它们实际上存在差异的地方......以及这些差异实际意味着什么.