Java类文件的创建是确定性的吗?
当使用相同的JDK(即相同的Java类文件的创建是确定性的吗?,java,compiler-construction,javac,Java,Compiler Construction,Javac,当使用相同的JDK(即相同的javac可执行文件)时,生成的类文件是否总是相同的?是否会因操作系统或硬件的不同而有所不同?除了JDK版本之外,还有其他因素导致差异吗?有没有避免差异的编译器选项?这仅仅是理论上的差异,还是Oracle的javac实际上为相同的输入和编译器选项生成了不同的类文件 更新1我感兴趣的是生成,即编译器输出,而不是类文件是否可以在各种平台上运行 update2用“相同的JDK”,我也指相同的javac可执行文件 更新3Oracle编译器中理论差异和实际差异的区别 [编辑,添
javac
可执行文件)时,生成的类文件是否总是相同的?是否会因操作系统或硬件的不同而有所不同?除了JDK版本之外,还有其他因素导致差异吗?有没有避免差异的编译器选项?这仅仅是理论上的差异,还是Oracle的javac
实际上为相同的输入和编译器选项生成了不同的类文件
更新1我感兴趣的是生成,即编译器输出,而不是类文件是否可以在各种平台上运行
update2用“相同的JDK”,我也指相同的javac
可执行文件
更新3Oracle编译器中理论差异和实际差异的区别
[编辑,添加释义问题]“在什么情况下,相同的javac可执行文件在不同的平台上运行时会产生不同的字节码?”编译器没有义务在每个平台上产生相同的字节码。您应该咨询不同供应商的
javac
实用程序以获得具体答案
我将展示一个关于文件排序的实际示例 假设我们有两个jar文件:
my1.jar
和My2.jar
。它们并排放在lib
目录中。编译器按照字母顺序读取它们(因为这是lib
),但如果文件系统不区分大小写,则顺序是my1.jar
,My2.jar
,如果文件系统区分大小写,则顺序是my1.jar
my1.jar
有一个带有方法的类a.class
public class A {
public static void a(String s) {}
}
My2.jar
具有相同的A.class
,但具有不同的方法签名(接受对象
):
很明显如果你有电话
String s = "x";
A.a(s);
它将在不同的情况下编译具有不同签名的方法调用。因此,根据文件系统的大小写敏感度,您将得到不同的类。答案很可能是“是”,但要得到准确的答案,您确实需要在编译过程中搜索一些键或guid生成 我不记得发生这种情况的情况了。例如,为了进行序列化,ID是硬编码的,即由程序员或IDE生成 另外,JNI也很重要
p.p.S.我发现
javac
本身就是用java编写的。这意味着它在不同的平台上是相同的。因此,它不会无缘无故地生成不同的代码。因此,它只能在本机呼叫中执行此操作。简短回答-否
长话短说 它们
字节码
对于不同的平台不必相同。是JRE(Java运行时环境)知道如何准确地执行字节码
如果您阅读了,您将了解到这不一定是真的,因为字节码对于不同的平台是相同的
在这里,它将类文件的结构显示为
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<2.0<2.1。爪哇
虚拟机实现可以支持
版本v当且仅当v位于某个连续范围Mi.0 v
Mj.m。只有Sun可以指定Java虚拟机的版本范围
符合特定版本的机器实施
Java平台可能支持.1
阅读更多的脚注
1 Sun JDK 1.0.2版的Java虚拟机实现
支持45.0至45.3版本(含)的类文件格式。太阳的
JDK发行版1.1.X可以支持中版本的类文件格式
范围为45.0至45.65535(含)。版本1.2的实现
Java 2平台的一个组件可以支持中版本的类文件格式
范围为45.0到46.0(含45.0)
因此,调查所有这些表明,在不同平台上生成的类文件不必完全相同。我相信,如果使用相同的JDK,生成的字节码将始终相同,与所使用的硬件和操作系统无关。字节码生成由java编译器完成,它使用确定性算法将源代码“转换”为字节码。因此,输出总是相同的。在这些情况下,只有对源代码的更新才会影响输出。
Java允许您在一个平台上编写/编译代码,并在不同的平台上运行。
AFAIK;只有当在不同平台上生成的类文件相同或技术上相同(即相同)时,这才可能实现
编辑
我所说的技术上相同的评论的意思是。如果逐字节比较,它们不需要完全相同
因此根据规范。不同平台上的类的类文件不需要逐字节匹配。我们这样说:
我可以很容易地生成一个完全一致的Java编译器,在给定相同的.Java
文件的情况下,它不会两次生成相同的.class
文件
我可以通过调整各种字节码结构或简单地向方法中添加多余的属性(这是允许的)来做到这一点
鉴于该规范不要求编译器生成逐字节相同的类文件,我将避免
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];
}
Can there be a difference depending on the operating system or hardware?
What are the circumstances where the same javac executable, when run on a different platform, will produce different bytecode?