您好我想知道有多少Java类文件在不同的编译器中发生变化。因此,如果.java文件是通过Sun JDK 1.4,1.5 1.6甚至IBM JDK编译的,那么实际字节会改变多少。我知道类文件在调试信息和模糊处理方面可能有所不同,但我们假设这些选项是相同的,所以包含调试信息,没有混淆。如果我在JDK 1.4编译的.class文件上运行MD5或SHA-1,那么如果我在JDK 1.5中编译它,那么Hash会有所不同,但是当定位JDK 1.5时,目标是1.4?
还与此相关,当使用不同的依赖关系时,类文件的二进制文件是否会发生更改,或者以不同的方式询问类文件的二进制文件是否会根据其依赖关系进行更改?
最后但并非最不重要的是有程序化方法来分析.class文件的元数据,以便识别编译时使用的编译器版本和/或开关?
答案 0 :(得分:5)
从源代码创建类和字节码时,Java编译器有相当大的自由度。他们可以重新排序方法,重新排序常量池(使用类名,方法名和字符串 - 这也导致不同的方法字节代码)并重新排序实际的字节代码命令,只要执行它们时的结果是相同的。
因此,使用MD5或类似的哈希来证明来自同一来源的两个类文件并不是真的合理。
答案 1 :(得分:2)
有关课程文件的格式,请参阅http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
是的,类文件可以并且通常会根据用于构建它们的特定编译器进行更改。有许多编译器实现细节将导致不同的字节码 - 例如在interfaces []或fields []数组中以不同顺序列出依赖项。 Plus编译器可以自由使用不同的优化。
添加或删除“import”语句不一定会更改类文件 - 但在一个包中使用一个类而不是另一个包肯定会。不确定这是否能回答你的第二个问题。
我不相信编译器会在类文件中留下他们的身份。任何这样的分析都需要是间接的,最有可能是启发式的(按照其风格告诉作者一本书) - 除非你有源代码并且可以用每个编译器进行编译并进行比较。
答案 2 :(得分: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
}
}