我有一个我们在内部编写的工具来为我们的应用程序创建补丁。它在scm中检查哪些类被更改了,并使用javac
编译它们。
然后将创建的jar添加到类路径中。在过去,我们发现了一个问题:如果我在类A中改变了方法返回类型,类B使用了这个方法,那么类A的签名就改变了,当类B调用这个方法时,我们得到NoSuchMethodError
。
然而,现在我有一个不同的情况,类静态变量被改变,我得到:java.lang.NoClassDefFoundError: Could not initialize class
。
你知道是什么原因造成的吗?
当一个类被更改时,是否有任何方法可以告诉我需要编译哪些类?
听起来开发一个我怀疑不可靠的解决方案需要花费很多精力。
我会为每个版本构建整个应用程序。要创建一个补丁,我会将生成的类或文件与原始发行版中的类或文件进行比较。
这个比较好,因为
- 你不需要理解改变一个常量、方法或类的所有后果。
- 如果你改变了一些偶然的东西,比如格式或注释,不需要更新文件。
- 你可以有信心,应用补丁是完全相同的,并给出一个完整的分布。
此外,public
常量的内联可能是难以定位的问题的来源,因为它们不会导致异常或错误,但会导致无声的错误行为。
假设你有一个类 a ,它有一些public static final
字段,它们是原始类型或String
类型,它们的值可以在编译时确定。
public class A {
public static final String GREETING = "Hello";
...
}
然后,如果另一个类B访问该字段,编译器内联该常量——即用"Hello"
替换A.GREETING
引用。不保留常量值从哪里来的信息。
现在麻烦来了——如果你把GREETING
的值改成"Hi"
,然后只重新编译类A,类B中的内联值将保持不变,直到你重新编译它。因此,对于,从头开始重新构建整个应用程序通常是一个更好的主意,正如其他人已经指出的那样。一篇讨论这个问题的好文章:http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html
相关SO问题:
如果Java可以在编译时确定内联字符串常量,那么Java是否保证使用它们
所有编译时常量都是内联的吗?
如果您更改类A的签名,您不仅需要重新编译所有调用该类的类。你必须改变这些类的实现。
例如,如果类A的方法foo()
被类B调用,现在你把它的名字改为bar()
,你必须改变类B的源代码,否则你会得到NoSuchMethodError
。
然而,如果你不改变接口,而只是修改类A的内部实现,你不需要重新编译任何东西,除了这个类本身。您只需要在编译时创建适当的类路径。类路径必须包括类A的直接依赖项和依赖项的依赖项。它不能包含第三级依赖(即依赖的依赖)。但是在编译补丁时处理类路径的最简单方法是提供现有应用程序的完整类路径。