当前位置: 首页 > 知识库问答 >
问题:

Java类文件的创建是确定性的吗?

蔺昊穹
2023-03-14

当使用相同的JDK(即相同的javac可执行文件)时,生成的类文件是否总是相同的?是否会因操作系统或硬件的不同而有所不同?除了JDK版本之外,还有其他因素导致差异吗?有没有避免差异的编译器选项?这仅仅是理论上的差异,还是Oracle的javac实际上为相同的输入和编译器选项生成了不同的类文件?

更新1我感兴趣的是生成,即编译器输出,而不是类文件是否可以在各种平台上运行。

更新2同样的JDK,我也指同样的javac可执行文件。

更新3 Oracle编译器中理论差异和实际差异之间的区别。

[编辑,添加转述问题]
“在什么情况下,相同的javac可执行文件在不同的平台上运行时,会产生不同的字节码?”

共有3个答案

寇和璧
2023-03-14

简短回答-否

对于不同的平台,它们的字节码不需要相同。JRE(Java运行时环境)知道如何准确地执行字节码。

如果您浏览JavaVM规范,您会知道这不一定是真的,不同平台的字节码是相同的。

通过查看类文件格式,它将类文件的结构显示为

ClassFile {
    u4 magic;
    u2 minor_version;
    u2 major_version;
    u2 constant_pool_count;
    cp_info constant_pool[constant_pool_count-1];
    u2 access_flags;
    u2 this_class;
    u2 super_class;
    u2 interfaces_count;
    u2 interfaces[interfaces_count];
    u2 fields_count;
    field_info fields[fields_count];
    u2 methods_count;
    method_info methods[methods_count];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

检查次要版本和主要版本

次要版本,主要版本

次要版本和主要版本项的值是此类文件的次要版本号和主要版本号。主版本号和次版本号共同决定类文件格式的版本。如果类文件有主版本号M和次版本号M,我们将其类文件格式的版本表示为M.M。因此,类文件格式的版本可以按字典顺序排列,例如1.5

阅读更多的脚注

1 Sun JDK 1.0.2版的Java虚拟机实现支持类文件格式版本45.0到45.3(含45.3)。Sun的JDK发行版1.1。X可以支持45.0到45.65535(含45.0)版本的类文件格式。Java 2平台1.2版的实现可以支持45.0到46.0(含45.0)版本的类文件格式。

因此,调查所有这些表明,在不同平台上生成的类文件不一定相同。

鞠安民
2023-03-14

编译器没有义务在每个平台上生成相同的字节码。您应该咨询不同供应商的javac实用程序以获得具体答案。

我将展示一个文件排序的实际例子。

假设我们有两个jar文件:my1.jarMy2.jar。它们并排放在lib目录中。编译器按字母顺序读取它们(因为这是lib),但是当文件系统不区分大小写时,顺序是my1.jarMy2.jar,并且My2.jarmy1.jar如果它区分大小写。

my1。jar有一个类a.class和一个方法

public class A {
     public static void a(String s) {}
}

My2。jar具有相同的A.class,但具有不同的方法签名(接受对象):

public class A {
     public static void a(Object o) {}
}

很明显如果你有电话

String s = "x"; 
A.a(s); 

它将在不同的情况下编译具有不同签名的方法调用。因此,根据文件系统对大小写的敏感程度,您将得到不同的类。

管峻
2023-03-14

让我们这样说:

我可以很容易地生成一个完全一致的Java编译器,它从不生成相同的。如果给定相同的,则两次初始化文件。java文件。

我可以通过调整各种字节码结构或简单地向我的方法添加多余的属性(这是允许的)来做到这一点。

鉴于规范不要求编译器产生字节对字节相同的类文件,我将避免依赖这样的结果。

然而,我检查了几次,用相同的编译器编译相同的源文件,使用相同的开关(和相同的库!)确实导致了相同的. class文件。

更新:我最近无意中看到了这篇有趣的博客文章,内容是关于Java 7中Stringswitch的实现。在这篇博文中,有一些相关的部分,我将在这里引用(我的重点):

为了使编译器的输出可预测且可重复,这些数据结构中使用的映射和集是LinkedHashMaps和LinkedHashSets,而不仅仅是HashMapshashset。就给定编译期间生成的代码的功能正确性而言,使用HashMapHashSet就可以了;迭代顺序并不重要。然而,我们发现让javac的输出不因系统类的实现细节而变化是有益的。

这非常清楚地说明了问题:编译器不需要以确定性的方式操作,只要它符合规范。然而,编译器开发人员意识到尝试一下通常是个好主意(前提是它可能不会太贵)。

 类似资料:
  • 问题内容: 当使用 相同的JDK (即相同的可执行文件)时,生成的类文件是否始终相同?取决于 操作系统 或 硬件 ,会有所区别吗?除JDK版本外,是否还有其他因素导致差异?是否有任何编译器选项来避免差异?是仅在理论上可能有所不同,还是Oracle 实际上针对相同的输入和编译器选项生成了不同的类文件? 更新1 我对 生成 感兴趣,即对编译器输出感兴趣,而不对是否可以在各种平台上 运行 类文件感兴趣。

  • 问题内容: 在StackOverflow上还有一个类似的问题要问(如何在Java中获取文件的创建日期),但实际上并没有答案,因为OP具有可以通过其他机制解决的不同需求。我试图在目录中创建文件列表,该文件列表可以按年龄排序,因此需要文件创建日期。 在大量浏览网络后,我还没有找到执行此操作的任何好方法。是否有获取文件创建日期的机制? 当前在Windows系统上的BTW可能也需要在Linux系统上工作。

  • 问题内容: malloc 是确定性的吗?假设我有一个分叉的进程,即另一个进程的副本,并且在某个时候它们都调用了 malloc 函数。在两个过程中分配的地址是否相同?假设执行的其他部分也是确定性的。 注意:在这里,我只谈论虚拟内存,而不是物理内存。 问题答案: 完全没有理由要使它具有确定性,实际上,没有确定性可以带来一些好处,例如,增加利用漏洞的复杂性(另请参见本文)。 这种随机性可能有助于使漏洞更

  • 问题内容: 我了解python集的元素没有顺序。调用pop方法将返回一个任意元素;我很好。 我想知道的是,当集合具有相同的历史记录时,pop是否总是返回相同的元素。当然,在一个版本的python中,我不介意不同版本的python实现自己的事情。特别是,我问的是python 2.7。在这种情况下,这比api的实现问题更多。 我在游戏的程序地牢生成器中大量使用了set,​​我希望结果对于给定的种子是确

  • 问题内容: 即,您如何从文本(xml / txt,独立于编码)中分辨出存档文件(jar / rar / etc。)? 问题答案: 没有保证的方法,但是有两种可能: 在文件上查找标题。不幸的是,标头是特定于文件的,因此尽管您可能能够发现它是RAR文件,但您将无法获得更通用的答案,无论是文本还是二进制。 计算字符与非字符类型的数量。文本文件将主要是字母字符,而二进制文件(尤其是压缩文件,如rar,zi

  • 朋友们,我有一段代码,它读取文本文件并搜索匹配的单词,但在搜索文本文件时存在不确定性。有时它能够匹配单词,有时它不能,尽管单词存在于文本文件中。 代码如下: 以下是我的文本文件内容: 有人知道为什么会这样吗?假设我在文本文件中添加一个单词“finish”,然后搜索它,它总会找到它。但是,如果我的搜索词是“dadas”或“dadist”,则在et中生成null。