Ant不会重新编译常量

时间:2011-06-21 18:14:19

标签: java ant

我有一个涉及类GUIConstants的Java项目 - 用于布局GUI的各种public static final参数,因为不同的组件有时必须是相同的大小或颜色或其他。

我目前正处于进行视觉重新设计的阶段,其中包括更改其中的一些常量。但是,ant使这很困难。我将更改参数并重新编译,但仍使用旧值。如果我对其中一个使用它并重新编译的文件添加一些微不足道的修改,将使用正确的值。但是,必须追踪所有文件并修改它们,这很烦人且容易出错。当然有办法迫使ant重新编译未更改的文件......我在手册页中找不到它。

旁注:我的假设是,当编译使用final变量的类时,Java会使用值本身,而不是对变量所指向的任何内容的引用(以与使用方式类似的方式)常量#DEFINE适用于C)。因此,即使变量指向其他内容,原始值也会被烘焙到.class文件中。这是真的? (这不会影响我的问题,我只是很好奇。)

提前致谢。

5 个答案:

答案 0 :(得分:2)

你的理论是错误的。 Java将决赛嵌入周围类文件的常量池中,就像任何非决赛一样。没有特殊的“最终”优化,除了一个标志,表明它只能在施工期间设置。

您的构建链中存在某种错误,例如从旧源“更新”的类或一组类,或者从尚未更新的类“构建”的jar文件,错误要好得多,或者从以前的版本中引用jar文件的程序等。验证这一点的一种快速方法是删除所有已编译的项目。通常这是通过ant build.xml文件中的“clean”目标完成的;但是,该目标也可以手写,所以不要认为它总是正确的(特别是如果你添加额外的中间构建步骤,如类增强等)。

答案 1 :(得分:2)

你的假设几乎是正确的。它不仅仅是final变量,而是所谓的“constant variables”:

  

我们调用一个原始类型或类型String的变量,它是final,并用编译时常量表达式(§15.28)初始化一个常量变量。变量是否是常量变量可能会影响类初始化(§12.4.1),二进制兼容性(§13.1§13.4.9)和明确赋值(§16

然后在binary compatibility (§13.1)

部分
  

对作为常量变量的字段(第4.12.4节)的引用在编译时被解析为表示的常量值。二进制文件中的代码中不应该存在对这样的常量字段的引用(包含常量字段的类或接口除外,它将具有初始化它的代码)

和(§13.4.9)(我的重点):

  

如果字段是常量变量(§4.12.4),则删除关键字final或更改其值不会破坏与预先存在的二进制文件的兼容性,导致它们不能运行,但是除非重新编译,否则他们不会看到使用该字段的任何新值。

在之前的工作中,我们使用了这种工具来创建一种条件编译系统,这样我们就可以生成生产二进制文件,并删除所有调试语句。

当你将它与javac task确定要重新编译的类的方式结合起来时,你得到了你所看到的行为:

  

只会编译没有相应的.class文件或类文件比.java文件旧的Java文件。

     

注意:Apache Ant仅使用源文件和类文件的名称来查找需要重建的类。它不会扫描源,因此不了解嵌套类,命名与源文件不同的类,等等。请参阅<depend>任务,以获取基于存在/修改时间以外的依赖性检查。

解决这个问题的最简单方法是每次执行干净的完整编译,例如ant clean compile(假设你有clean目标,删除所有类文件)。这可能太慢了。

我还建议你按照javac任务的文档中的建议查看depend任务,但查看文档(我实际上没有使用过它)我觉得它似乎无济于事(参见标题为“限制”的部分):

  

这些限制最明显的例子是,当其他类导出的常量基本数据类型发生更改时,任务无法判断要重新编译哪些类。

一种可能的解决方法,如果你发现每次进行一次干净的编译太慢,就会使GUIConstants类中的值不是常量,至少在你做出改变的时候。您可以通过注释掉所有final关键字使值成为非最终值,然后其他类应该看到您的更改。当您对新值感到满意时,将final重新放入并重新编译(并测试当然一切仍然正常)。

答案 2 :(得分:1)

您想使用删除dist目录中所有文件的clean任务。或者无论你碰巧放置二进制文件。

答案 3 :(得分:0)

两种“理论”看起来都不正确,删除静态没有效果,从清洁中重新编译总是有效,我的构建“系统”几乎只依赖于子目录中的源代码并且没有其他外部罐子,没有“陈旧” “班上闲逛

在我的情况下,我必须完全重建我的源的一个区域 - 我直接包括来自源的库,它不需要重新编译但是被单独的“deepclean”规则包含但是被隔离从这个问题......

答案 4 :(得分:0)

DJClayworth在这个answer中的答案建议使用类似下面的结构来欺骗编译器:

public static final int INT_VALUE = Integer.valueOf(100).intValue();

它使编译器看不到此成员的常量字符。我只是测试它,它的工作原理。将常量更改为上述构造后,不要忘记执行一次完整的清理。

不是一个漂亮的解决方案,但对于暂时的解决方法很有用。