当类更改时我需要编译哪些类?
我有一个我们内部编写的工具,可以为我们的应用程序创建补丁。 它在 scm 中检查哪些类已更改,并使用 javac
编译它们。
然后我们将创建的 jar 添加到类路径中。 过去我们发现这样有一个问题: 如果我更改了 A 类中的方法返回类型,并且 B 类使用该方法,则 A 类签名发生更改,并且当 B 类调用该方法时我们会收到 NoSuchMethodError
。
但是,现在我有一个不同的情况,类静态变量被更改,我得到: java.lang.NoClassDefFoundError:无法初始化类
。
你知道是什么原因造成的吗?
当类更改时,有什么方法可以告诉我需要编译哪些类?
I have a tool we wrote internal to create patches for our application.
It checks in scm what classes were changed and compile them using javac
.
Then we add the created jar to the classpath.
In the past we discovered that there is a problem with that:
If I changed method return type in class A, and class B uses that method then the class A signature changed and we get NoSuchMethodError
when class B call that method.
However, now I have a different case that class static variables were changed and I get:java.lang.NoClassDefFoundError: Could not initialize class
.
Do you know what is causing this?
Is there any way to tell which classes I need to compile when a class was changed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
听起来好像花了很多精力来开发一个我怀疑不可靠的解决方案。
我将为每个版本构建整个应用程序。为了创建补丁,我会将生成的类或文件与原始发行版中的类或文件进行比较。任何已更改的文件都将包含在内。
这更好,因为
It sounds like a lot of effort to develop a solution I suspect is unreliable.
I would build the whole application, for every release. To create a patch, I would compare the class or file produced against that in the original distribution. Any files which have changed would be included.
This is better because
此外,
public
常量的内联可能是难以定位的问题的根源,因为它们不会导致异常或错误,但会导致无声的错误行为。假设您有一个类 A ,其中包含一些
public static final
字段,这些字段属于原始类型或String
,其值可以在编译时间。然后,如果另一个类B访问该字段,编译器会内联该常量 - 即用其值
“Hello”
替换A.GREETING
引用。不保留恒定值来自何处的信息。现在麻烦来了 - 如果您将
GREETING
的值更改为"Hi"
并仅重新编译类 A,则内联值类 B 将保持不变,直到您重新编译它。因此,正如其他人已经指出的那样,从头开始重建整个应用程序通常是一个更好的主意。一篇很好的文章讨论了这个问题:
http://marxsoftware.blogspot.com/2009/09/ inconstant-constants-in-java.html
一些相关的SO问题:
Java 是否保证内联字符串常量(如果可以在编译时确定)
是所有编译时常量都内联吗?
Also, inlining of
public
constants may be a source of problems that are hard to target, since they don't cause exceptions or errors, but cause silent wrong behaviour.Lets say you have a class A with some
public static final
fields that are of a primitive type or aString
and whose values can be determined at compile time.Then if another class B accesses this field, the compiler inlines the constant - i.e. replaces the
A.GREETING
reference with its value"Hello"
. No information of where the constant value comes from is kept.Now comes the trouble - if you change the value of
GREETING
to lets say"Hi"
and recompile only the class A, the inlined value in class B will remain unchanged until you recompile it too. Therefore, it is usually a better idea to rebuild the entire application from scratch, as others have already pointed out.A nice article discussing this problem:
http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html
Some related SO questions:
Is Java guaranteed to inline string constants if they can be determined at compile time
Are all compile-time constants inlined?
如果更改 A 类的签名,您不仅需要重新编译调用该类的所有类。您必须更改这些类的实现。
例如,如果类 A 具有由类 B 调用的方法
foo()
,现在将其名称更改为bar()
,则必须更改类的源代码B. 否则你会得到NoSuchMethodError
。但是,如果您不更改接口而只是修改类 A 的内部实现,则除了此类本身之外,您无需重新编译任何内容。您只需在编译时创建适当的类路径即可。类路径必须包含类A的直接依赖关系和依赖关系的依赖关系。它不能包含第三级依赖关系(即依赖关系的依赖关系的依赖关系)。但恕我直言,在编译补丁时处理类路径的最简单方法就是提供现有应用程序的完整类路径。
If you change signature of class A you do not just have to recompile all classes that call this class. You have to change the implementation of these classes.
For example if you class A had method
foo()
that was called by class B and now you change its name tobar()
you have to change the source code of class B. Otherwise you will getNoSuchMethodError
.If however you do not change interfaces but just modify the internal implementation of class A you do not have to recompile anything except this class itself. You just have to create appropriate classpath when compiling. The class path must include direct dependencies of class A and dependencies of dependencies. It must not contain 3rd level dependencies (i.e. dependencies of dependencies of dependencies). But IMHO the easiest way to deal with class path when compiling the patch is just provide the full classpath of existing application.