蚂蚁不会't重新编译常量



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

我目前正处于进行视觉重新设计的阶段,其中包括更改其中一些常量。然而,ant使这一点变得困难。我将更改一个参数并重新编译,但仍使用旧值。如果我对其中一个使用它的文件添加一些琐碎的修改并重新编译,就会使用正确的值。但是,必须跟踪所有文件并对其进行修改,这很烦人,而且容易出错。当然,有一种方法可以强制ant重新编译未更改的文件。。。我只是在手册页找不到它。

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

提前谢谢。

你的假设几乎是正确的。它不是简单的final变量,而是所谓的";常量变量":

我们将一个基元类型或String类型的变量称为常量变量,该变量是final并用编译时常量表达式(§15.28)初始化。变量是否为常变量可能涉及类初始化(§12.4.1)、二进制兼容性(§13.1、§13.4.9)和确定赋值(§16)。

然后在二进制兼容性部分(§13.1):

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

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

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

在之前的工作中,我们利用这一点建立了一种条件编译系统,这样我们就可以在去掉所有调试语句的情况下生成生产二进制文件。

当您将其与javac任务确定要重新编译哪些类的方式相结合时,您会得到您所看到的行为:

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

注意:ApacheAnt只使用源文件和类文件的名称来查找需要重建的类。它不会扫描源,因此对嵌套类、与源文件命名不同的类等一无所知。有关基于存在/修改时间以外的依赖性检查,请参阅<depend>任务。

解决此问题的最简单方法是每次使用类似ant clean compile的东西进行干净的完全编译(假设您有一个clean目标,它会删除所有类文件)。不过这可能太慢了。

我还建议您查看depend任务,正如javac任务的文档中所建议的那样,但查看它的文档(我自己实际上还没有使用过它)似乎没有帮助(请参阅标题为"限制"的部分):

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

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

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

在构建链中出现某种错误的可能性要大得多,比如从旧源"更新"的类或类集,或者从尚未更新的类"构建"的jar文件,或者引用以前构建的jar文件的程序,等等。验证这一点的一种快速方法是删除所有编译项。这通常是通过ant build.xml文件中的"clean"目标来完成的;但是,这个目标也可能是手工编写的,所以不要认为它总是正确的(尤其是如果您添加了额外的中间构建步骤,如类增强等)。

您希望使用clean任务来删除dist目录中的所有文件。或者放二进制文件的地方。

这两个"理论"似乎都不正确,删除静态没有任何效果,从clean重新编译总是有效的,我的构建"系统"几乎是锅炉板,只依赖子目录中的源代码,没有其他外部jar,周围没有"过时"的类

在我的情况下,我必须对我的源代码的一个区域进行完全重建-我直接从源代码中包含一个库,该库不需要重新编译,但由单独的"深度清理"规则包含,但与此问题无关。。。

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

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

它使编译器看不到此成员的常量字符。我刚刚测试过它,它有效。在将常量更改为上面的构造后,不要忘记执行一个完整的clean。

这不是一个漂亮的解决方案,但对于临时解决方案来说很好。

最新更新