2011-12-25 37 views
1

我有一个我们写的内部工具来为我们的应用程序创建补丁。 它在scm中检查哪些类已更改并使用javac进行编译。
然后我们将创建的jar添加到类路径中。 在过去,我们发现有一个问题: 如果我改变了A类中的方法返回类型,并且B类使用了那个方法,那么A类签名改变了,当B类调用该方法时,我们得到NoSuchMethodError
但是,现在我有一个不同的情况,类静态变量发生了变化,我得到: java.lang.NoClassDefFoundError: Could not initialize class
你知道这是什么原因吗?
有没有什么办法可以告诉我们在更改类时需要编译哪些类?当班级改变时,我需要编译哪些类?

+1

我想知道,如果它不会是更容易重新编译一切,使用diff工具来查找实际更改的二进制文件。 – 2011-12-25 11:25:46

+0

我已阅读了有关此问题的几个详细讨论。简单的答案是,知道需要重新编译的东西并不简单,并且没有独立的工具可以实现。 Eclipse增量式编译器可以做到这一点,但只能作为编译的一部分。 @ JensSchauder的建议看起来很不错。 – 2011-12-25 15:07:08

回答

4

这听起来像是很多努力来开发我怀疑是不可靠的解决方案。

我会为每个版本构建整个应用程序。要创建一个补丁,我会比较生成的类或文件与原始发行版中的类或文件。任何已更改的文件都将包含在内。

这是更好,因为

  • 你不必了解不断变化的一个常数,方法或类的所有后果。
  • 如果您更改偶然的格式或注释等内容,则无需更新文件。
  • 你可以有信心,应用补丁是完全一样的,并给予完整的分布。
1

如果更改类A的签名,则不必重新编译调用此类的所有类。你必须改变这些类的实现。

例如,如果你的A类有方法foo()这是所谓的B类,现在你更名为bar()你必须改变B类的源代码,否则你会得到NoSuchMethodError

但是,如果您不改变接口但只是修改类A的内部实现,则不必重新编译除此类之外的任何内容。编译时只需创建适当的类路径。类路径必须包含类A的直接依赖关系和依赖关系的依赖关系。它不能包含第三级依赖关系(即依赖关系依赖关系的依赖关系)。但恕我直言,编译补丁时处理类路径的最简单方法就是提供现有应用程序的完整类路径。

+1

有些签名更改可以简单地重新编译(至少有一些)用法,而无需更改任何源 - 例如,如果返回类型仍可分配给之前使用的相同类型,或者参数类型现在更宽。类似于常量的变化。 – 2011-12-25 11:34:16

3

此外,内联public常量可能是难以定位的问题的来源,因为它们不会导致异常或错误,但会导致沉默的错误行为。

比方说你有一个类一个一些public static final字段是一个基本类型或一个String的,其值可以在编译时确定。

public class A { 
    public static final String GREETING = "Hello"; 
    ... 
} 

然后,如果另一个类访问该字段,编译器内联常数 - 即将A.GREETING参考替换为其值"Hello"。没有关于恒定值来自哪里的信息。

现在到了麻烦 - 如果你改变GREETING价值可以说"Hi"并重新编译只有类一个,直到你重新编译过的类内联值将保持不变。因此,像其他人已经指出的那样,从零开始重建整个应用程序通常是一个更好的主意

一个很好的文章讨论这个问题: http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html

一些相关的SO问题:

Is Java guaranteed to inline string constants if they can be determined at compile time

Are all compile-time constants inlined?

相关问题