我正在尝试确定是否需要在构建链中重新编译一些jar,如果我有例如以下结构,jar 1在其'source更改时编译,jar 2在其'source更改时或jar时编译1已重新编译。
jar 1:
public class Foo /* impl*/
jar 2:
public class Bar extends Foo /*impl*/
假设两个班级之间的合同没有改变,即。添加抽象方法或将方法添加到接口等
我需要重新编译jar 2吗?即。如果对Foo中的私有方法进行了一些更改,Bar需要重新编译吗?
我尝试通过在一组中更改一堆之后比较两个类的字节码来测试它,并且正如预期的那样它没有改变。然而,我的同事坚持认为他们遇到过这样的情况:即使合同没有改变,他们也必须重新编译一切才能工作,但是他们不记得原因是什么......所以举证责任在我身上证明了这不应该是必要的。 是否存在更改超类需要重新编译子类的情况,即使两者之间的接口保持不变也是如此?
答案 0 :(得分:6)
假设Foo
由开源组织发布;各种公司实施了数以千计的Foo
子类。
现在,如果对Foo
进行了一些更改,并且以二进制形式发布了新版本,那么所有公司都应该重新编译它们的代码吗?当然不是。 (好吧,我们一直在重新编译所有代码,但这不是必需的 - 可以简单地放入Foo
的新jar而不会导致任何问题)
这是二进制兼容性问题,您可以查看规范以确保对Foo
的更改是安全的。见http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html
答案 1 :(得分:3)
一般情况下,您必须重新编译依赖类。但是,如果您未更改Foo
使用的Bar
的任何方法或字段,则在更改Bar
时无需重新编译Foo
。
例如,Foo
protected int foo()
调用方法Bar
,但您将其签名更改为protected String foo()
或将其可见性更改为private
,则必须重新设置Bar
- 编译Bar
。在这种情况下,Bar
无法编译:您必须更改其代码。
但是,如果foo()
未使用方法foo()
或仅更改了Bar
的实施细节,则可以使用{{1}}而无需重新编译。
答案 2 :(得分:2)
绝对不会。您可以使用打包在jar文件中的框架(包含许多类似于Foo的合同的类),而不需要从源代码编译它们。但是你需要绝对确保合同没有直接间接改变。间接变化的一些例外:
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;
}
}
如果不重新编译类Bar,它仍将使用值1.