不同编译器、版本、依赖项下的 java .class 文件有什么差异?

问题描述 投票:0回答:3

嗨,我想知道 Java 类文件在不同的编译器中发生了多少变化。那么,如果 .java 文件是由 Sun JDK 1.4、1.5 1.6 甚至 IBM JDK 编译的,实际字节会发生多少变化。我知道类文件在调试信息和混淆方面可能有所不同,但我们假设这些选项是相同的问题,因此包含调试信息,没有混淆。如果我在 JDK 1.4 编译的 .class 文件上运行 MD5 或 SHA-1,如果我在 JDK 1.5 中编译它但针对 1.4,那么当针对 JDK 1.5 时,哈希会有所不同吗?

与此相关的是,当使用不同的依赖项时,类文件的二进制文件是否会更改,或者以不同的方式询问,类文件的二进制文件是否可以根据其依赖项而更改?

最后但并非最不重要的一点是,是否有编程方法来分析 .class 文件的元数据,以便识别编译器版本和/或编译时使用的开关?

java class md5 bytecode
3个回答
5
投票

Java 编译器在从源代码创建类和字节码时具有相当大的自由度。他们可以重新排序方法,重新排序常量池(使用类名、方法名和字符串 - 这也会导致不同的方法字节码)并重新排序实际的字节码命令,只要执行它们时的结果是相同的。

因此,使用 MD5 或类似的哈希值来证明两个类文件来自同一源并不是真正明智的。


2
投票

类文件的格式请参见 http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html

是的,类文件可以而且通常确实会发生变化,具体取决于用于构建它们的特定编译器。有许多编译器实现细节会导致不同的字节码——例如在 Interfaces[] 或 fields[] 数组中以不同顺序列出依赖项。另外,编译器可以自由使用不同的优化。

添加或删除“导入”语句不一定会更改类文件——但在一个包中使用一个类而不是另一个包中的类肯定会更改。不确定这是否回答了您的第二个问题。

我不相信编译器会在类文件中留下它们的身份。任何此类分析都需要是间接的并且很可能是启发式的(就像通过书的风格告诉作者一样)——除非您拥有源代码并且可以使用每个编译器进行编译并进行比较。


1
投票

Paŭlo 很好地回答了你关于哈希的问题。至于你的另一个问题:

与此相关的是,当使用不同的依赖项时,类文件的二进制文件是否会更改,或者以不同的方式询问,类文件的二进制文件是否可以根据其依赖项而更改?

是的。类文件包含所有调用的方法的签名,这些签名可能已更改。考虑:

void test() {
    Foo.bar(1,2);
}

其中版本 1 中的 Foo 定义为:

class Foo {
    public static void bar(int x, int y) {
        // do something
    }
}

在版本 2 中由:

class Foo {
    public static <T> T bar(T... ts) {
        // do something
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.