java.class文件在不同的编译器、版本和依赖项之间的差异是什么?

java.class文件在不同的编译器、版本和依赖项之间的差异是什么?,java,class,compiler-construction,md5,bytecode,Java,Class,Compiler Construction,Md5,Bytecode,嗨,我想知道Java类文件在不同的编译器中有多少变化。那么,如果.java文件是由sunjdk1.4、1.51.6甚至ibmjdk编译的,那么实际的字节会有多大的变化呢。我知道类文件在调试信息和模糊处理方面可能不同,但是让我们假设这些选项是相同的,所以包含调试信息,没有模糊处理。如果我在JDK1.4编译的.class文件上运行MD5或SHA-1 has,那么如果我在JDK1.5中编译它,但目标是1.4,那么哈希会有所不同吗?当目标是JDK1.5时会怎样 同样与此相关的是,当使用不同的依赖项时,类

嗨,我想知道Java类文件在不同的编译器中有多少变化。那么,如果.java文件是由sunjdk1.4、1.51.6甚至ibmjdk编译的,那么实际的字节会有多大的变化呢。我知道类文件在调试信息和模糊处理方面可能不同,但是让我们假设这些选项是相同的,所以包含调试信息,没有模糊处理。如果我在JDK1.4编译的.class文件上运行MD5或SHA-1 has,那么如果我在JDK1.5中编译它,但目标是1.4,那么哈希会有所不同吗?当目标是JDK1.5时会怎样

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


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

有关类文件的格式,请参阅

是的,类文件可以而且通常会根据用于构建它们的特定编译器进行更改。有许多编译器实现细节将导致不同的字节码——例如,在接口[]或字段[]数组中以不同顺序列出依赖项。另外,编译器可以自由使用不同的优化

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


我不相信编译器会在类文件中留下他们的身份。任何这样的分析都需要是间接的,而且很可能是启发性的(在告诉一本书的作者它的风格时)——除非你已经有了源代码并且可以用每个编译器编译并比较。

有关类文件的格式,请参阅

是的,类文件可以而且通常会根据用于构建它们的特定编译器进行更改。有许多编译器实现细节将导致不同的字节码——例如,在接口[]或字段[]数组中以不同顺序列出依赖项。另外,编译器可以自由使用不同的优化

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


我不相信编译器会在类文件中留下他们的身份。任何这样的分析都需要是间接的,而且很可能是启发性的(在告诉一本书的作者它的风格时)——除非你已经有了源代码并且可以用每个编译器编译并比较。

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


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

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


因此,使用MD5或类似的散列来证明两个类文件来自同一个源并不明智。

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
    }
}
class-Foo{
公共静态T形杆(T…ts){
//做点什么
}
}

帕罗已经回答了你关于散列井的问题。至于你的另一个问题:

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

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

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
    }
}
class-Foo{
公共静态T形杆(T…ts){
//做点什么
}
}

MD5和SHA-1的定义方式是,如果您更改输入的一位,则可以更改大约一半的输出位。换句话说,如果这些类文件在哪怕一个字节上都不同,那么您将得到完全不同的MD5或SHA-1。MD5和SHA-1的定义方式是,如果您更改输入的一位,将更改其大约一半的输出位。换言之,如果这些类文件在一个字节内存在差异,您将得到完全不同的MD5或SHA-1。添加或删除导入本身不会改变依赖关系。事实上,导入根本不是依赖项。创建依赖关系的是外部类或类成员的实际显式或隐式使用。(有许多方法可以在不导入的情况下获得依赖关系。)添加或删除导入本身不会更改依赖关系。事实上,导入根本不是依赖项。创建依赖关系的是外部类或类成员的实际显式或隐式使用。(有许多方法可以让您在不导入的情况下拥有依赖关系。)