假设 JDK 版本、构建工具版本和构建/编译选项是相同的,我仍然可以想到许多可能的差异来源:
时间戳 - 类文件可能1包含编译时间戳。除非您在完全相同的时间运行编译,否则同一文件的不同编译将导致不同的时间戳。
源文件名路径 - 每个类文件都包含源文件的路径名。如果您用不同的路径名编译两棵树,则类文件将包含不同的源路径名。
导入的编译时常量的值 - 当一个类A
使用在另一个类B
中定义的编译时常量(参见 JLS 中“编译时常量”的定义)时,该常量的值将合并到A
s 类文件中。因此,如果您A
针对不同版本的B
(常量值不同)进行编译,则代码A
可能会有所不同。
由于编译器identityHashcode
在HashMap
键中使用的差异可能导致某些步骤中映射迭代顺序的差异。这可能会.class
以不显着的方式影响文件生成,但仍显示为.class
文件差异。例如,常量池条目可能以不同的顺序结束。
外部类/方法的签名差异;例如,如果您更改了其中一个 POM 文件中的依赖项版本。
有效构建类路径的差异可能会导致找到导入类的顺序不同。这可能反过来导致类文件的常量池中的条目顺序出现非显着差异。这可能由于以下原因而发生:
- 在外部 JAR 文件的目录中以不同顺序出现的文件,
- 由于构建工具迭代时源文件的顺序不同,文件以不同的顺序编译2,或者
- 构建中的并行性(如果您启用了该功能)。
文件排序问题有一个可能的解决方法:使用JDK-7003006-XDsortfiles
中描述的未记录选项。(感谢@Holger 知道这一点。)
请注意,您通常看不到文件系统目录中文件的实际顺序。命令行工具ls
和dir
文件浏览器通常会在显示条目之前对条目进行排序(按名称或时间戳顺序)。
1 - 这取决于编译器。此外,不能保证javap
会显示时间戳......如果它们存在的话。
2 - 操作系统不保证列出目录(在系统调用级别)将以确定的顺序返回文件系统对象......或相同的顺序,如果您已删除并重新添加文件。
I should add that the first step to identifying the cause of the differences is to work out exactly what they are. You probably need (needed) to do that the hard way - by manually decoding a pair of class files to identify the places where they actually differences ... and what the differences actually mean.