当前位置: 首页 > 面试题库 >

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

西门振
2023-03-14
问题内容

谁能解释相同的Java源代码最终如何编译成 二进制 不同的类文件?

问题来自以下情况:

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

最终结果是一组包含分支源的目录和一组包含中继源的目录。使用“超越比较”,我们能够确定两组来源相同。但是,在编译时(使用IntelliJ
v11中托管的maven的 同一JDK ),我们注意到大约十二个左右的类文件是不同的。

当我们为每对显然不同的类文件反编译源代码时,我们最终得到的是相同的java源代码,因此就最终结果而言,这似乎无关紧要。但是为什么只有几个文件不同呢?

谢谢。

附加思想:

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


问题答案:

假设JDK版本,html" target="_blank">构建工具版本和构建/编译选项相同,我仍然可以想到许多 可能 的差异来源:

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

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

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

  4. 由于编译器identityHashcodeHashMap键中使用的差异可能会在某些步骤中导致映射迭代顺序的差异。这可能.class以不重要的方式影响文件生成,但仍显示为.class文件差异。例如,常量池条目可能以不同的顺序结束。

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

  6. 有效构建类路径中的差异可能会导致找到导入类的顺序不同。反过来,这可能会导致类文件的“常量池”中条目的顺序发生非重大差异。发生这种情况的原因可能是:

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

对于文件排序问题,有一种可能的解决方法:-XDsortfiles如JDK-7003006中所述,使用未记录的选项。(对于@Holger知道这一点,表示感谢。)

请注意,您通常不会在文件系统目录中看到文件的实际顺序。命令行工具(例如ls和和dir)以及文件浏览器通常会在显示条目之前(以名称或时间戳顺序)对其进行排序。

1-这取决于编译器。另外,也不能保证javap会显示时间戳…如果存在的话。

2-操作系统不保证列出目录(在syscall级别)将以确定的顺序…或相同的顺序返回文件系统对象(如果已删除并重新添加文件)。

我应该补充说,找出造成差异的原因的第一步是准确找出差异的原因。您可能需要(需要)以困难的方式做到这一点-
通过手动解码一对类文件来识别它们实际存在差异的位置以及差异的实际含义。



 类似资料:
  • 问题内容: 在Java中,“二进制代码”与“ Java字节码”的含义相同吗? 这是Java中的流程吗? Java文件(.java)-> [javac]-> ByteCode文件(.class)-> [JVM / Java解释器]->运行它(首先将其转换为特定于机器的二进制代码) 谢谢! 问题答案: 答案取决于您的意思 。 是一种二进制数据格式,包括Java虚拟机的加载信息和执行指令。从这个意义上讲

  • 问题内容: 我注意到,在没有源代码编码声明的情况下,Python 2解释器假定源代码使用 脚本 和 标准输入 以ASCII编码: 并使用 模块 和 命令 标志在ISO-8859-1中进行了编码: 它在哪里记录? 与此相反,Python 3始终假定源代码是用UTF-8编码的,因此可以在四种情况下打印。 注意。 –我在控制台编码设置为UTF-8的macOS 10.13和Ubuntu Linux 17.

  • 我试图将paralleStream与自定义的ForkJoin池一起使用,该任务执行网络调用。当我使用以下样式时 如果使用parallelStream,那么ForkJoinPool.Common是否以某种方式参与其中?下面是模拟上述两种样式的整个程序

  • 问题内容: 如何将Android DEX(VM字节码)文件反编译为相应的Java源代码? 问题答案: It’s easy 获取以下工具: 1)dex2jar将dex文件转换为jar文件 2)jd-gui查看jar中的java文件 由于dex2jar进行了一些优化,因此源代码具有很高的可读性。 Procedure:: 这是有关如何反编译的过程: 步骤1: 将中的转换为 注1:在Windows计算机上

  • 问题内容: 给定相同的主要版本,例如Java 7,不同的Java编译器(例如Oracle的热点,JRockit或IBM的J9等)是否将给定的Java源代码文件编译为相同的bytcode? 扫描Java 7语言规范 ,似乎正在讨论的是语言的语义,而不是代码到字节码的转换。 YES 。 以上摘录为: JLS留下了许多实现细节,因一个实现而异。 和 但是,JLS没有指定从源代码到生成的字节码的1:1映射

  • 我偶然发现了一些毫无意义的东西。我有这个Python代码,它做2个简单的for循环,只是测量执行时间。然而,我发现从一个函数调用完全相同的代码需要一半的时间。有人能解释一下为什么吗? 这里是输出: