Java 如果父类/接口发生更改,类的字节码是否会更改?

Java 如果父类/接口发生更改,类的字节码是否会更改?,java,class,bytecode,Java,Class,Bytecode,我试图确定是否需要重新编译构建链中的一些jar,例如,如果我有以下结构,JAR1在其“源”更改时编译,JAR2在其“源”更改时编译,或者JAR1重新编译时编译 jar 1: public class Foo /* impl*/ jar 2: public class Bar extends Foo /*impl*/ 假设两个类之间的契约不变,即添加抽象方法或向接口添加方法等 我需要重新编译jar2吗?例如,如果对Foo中的私有方法进行了一些更改,Bar是否需要重新编译 我试图通过比较两个类的

我试图确定是否需要重新编译构建链中的一些jar,例如,如果我有以下结构,JAR1在其“源”更改时编译,JAR2在其“源”更改时编译,或者JAR1重新编译时编译

jar 1:

public class Foo /* impl*/
jar 2:

public class Bar extends Foo /*impl*/
假设两个类之间的契约不变,即添加抽象方法或向接口添加方法等

我需要重新编译jar2吗?例如,如果对Foo中的私有方法进行了一些更改,Bar是否需要重新编译


我试图通过比较两个类的字节码来测试这一点,在一个类中更改了一组字节码之后,正如预期的那样,它没有更改。然而,我的同事坚持说,他们遇到过这样的情况:即使合同没有更改,他们也必须重新编译所有内容才能正常工作,但他们不记得原因是什么。。。因此,我有责任证明这是不必要的是否存在这样一种情况,即即使两个子类之间的接口保持不变,对超类进行更改也需要重新编译子类?

在一般情况下,您必须重新编译依赖类。但是,如果您没有更改
Foo
Bar
使用的
Foo
的任何方法或字段,则在
Foo
发生更改时,您不必重新编译
Bar

例如,如果
Foo
有方法
protectedintfoo()
Bar
调用,但您将其签名更改为
protectedstringfoo()
或将其可见性更改为
private
,则必须重新编译
Bar
。在这种情况下,
Bar
无法编译:您必须更改其代码


但是,如果
Bar
不使用方法
foo()
,或者如果只更改了
foo()
的实现细节,您可以使用
Bar
,而无需重新编译。

当然不可以。您可以使用框架(其中包含许多具有类似foo的契约的类)它打包在jar文件中,您不需要从源代码处编译它们。但你们需要绝对确保合同并没有直接或间接地改变。一些间接变化的例子:

public class Foo { //v1
    public static final int CONSTANT = 1;         
}

public class Foo { //v2
    public static final int CONSTANT = 2;         
}

public class Bar extends Foo {
    private int a(int value) {
        switch (value) {
            case CONSTANT:
                return 1;
        }
        return 2;
    }
}

如果不重新编译类栏,它仍将使用值1

比如说
Foo
是由一个开源组织发布的;各种公司实现了数千个子类的
Foo

现在,如果对
Foo
进行了一些更改,并且以二进制形式发布了新版本,那么所有公司都应该重新编译代码吗?当然不是。(好吧,我们一直都在重新编译所有代码,但这不是必需的-只需插入
Foo
的新jar,就不会引起任何问题)


这是二进制兼容性的问题,您可以检查规范以确保对
Foo
的更改是安全的。请参见

更改Bar使用的Foo中的常量值也需要重新编译。此外,java有定义良好的规则。方法重载也存在潜在问题。显然,如果添加了重载方法,则在不重新编译的情况下将无法使用它。这是否意味着Bar.class文件将在其中包含
常量
int的值?我的直觉是,它只引用了
Foo/CONSTANT
,并将在运行时相应地更新。你知道为什么不是这样吗?如果你用的不是开关,可能是的。Switch指令需要显式的数字,而compile无法在运行时从常量字段读取值。感谢链接,我想我希望只要源代码没有更改,类文件就永远不需要更改。哦,好吧。