Java常量在不同的地方是不同的

Java常量在不同的地方是不同的,java,constants,Java,Constants,所以,我们已经把一些东西推向了生产阶段,而且运作良好。然而,我在日志中看到一些非常令人不安的东西。即: pr 0.1 - wait time for fetchAndRemoveEntries: 0 pr 1.0 - f'n'r entries: uid: hbyk68jfhbf5th 请注意,pr对于这两行是不同的。对fetchandremoveents运行代码搜索等待时间只返回一个结果,f'n'r entries。两者都是printlns。第一个是在我们的一个API类中发现的: Syst

所以,我们已经把一些东西推向了生产阶段,而且运作良好。然而,我在日志中看到一些非常令人不安的东西。即:

pr 0.1 -  wait time for fetchAndRemoveEntries: 0
pr 1.0 - f'n'r entries: uid: hbyk68jfhbf5th
请注意,
pr
对于这两行是不同的。对fetchandremoveents运行代码搜索
等待时间
只返回一个结果,
f'n'r entries
。两者都是
println
s。第一个是在我们的一个API类中发现的:

System.out.println("pr " + NotificationDataStorage.printReduction + " -  wait time for fetchAndRemoveEntries: " + (System.currentTimeMillis() - startTime));
第二个是在类NotificationDataStorage中找到的,其中定义了PrintReduce。该类的缩写版本:

public class NotificationDataStorage {
  public static final double printReduction = 1;
  ...
  public static void addEntries(ArrayList<HashMap> data) {
    ... // No, I have did not declare 'printReduction' as a local variable.)
    System.out.println("pr " + printReduction + " - adding " + data.size() + " entries");
    ...
  }
  ...
}
公共类通知数据存储{
公共静态最终双面打印减少=1;
...
公共静态无效补遗(ArrayList数据){
…//不,我没有将“PrintReduce”声明为局部变量。)
System.out.println(“pr”+PrintReduce+”-添加“+data.size()+”条目”);
...
}
...
}
即使忽略“addEntries”代码,NotificationDataStorage.PrintReduce返回0.1这一事实(实际上应该是1)也是非常值得关注的

事实上,我们整个星期都被类似的问题困扰着,尽管直到现在,当我们推到服务器时,这些问题总是消失了。我们认为它们是本地的怪癖,也许是NetBeans的缺陷。我在调试器中遍历了代码,在将常量传递到方法a时查看了它,并看到它在a的作用域内时会从以前的构建中更改为值。旧值导致代码崩溃。我将它设置为记录一些事情,问题就神秘地消失了。我们有一些代码莫名其妙地不起作用,但在签出另一个分支并签回不起作用的分支后,它突然又开始工作了。清洁和建筑有时会修复它。有时候不是

奇怪的是,据我所知,这是我们遇到这些问题的第一周。就好像一周前我们写了一些代码,这些代码的比特现在召唤出一个恶魔来扰乱我们的常数。或者更准确地说,当我们更新常数时,变化只反映在它们使用的某些地方

当前出现的特定问题没有问题,但其他常量可能会遇到类似的问题,这非常令人担忧


有人对此有什么见解、经验或解释吗?

这几乎可以肯定是因为并不是所有的代码都得到了重新编译

您的字段是
publicstaticfinaldouble
,它将在编译时内联值。如果值发生变化,这将是一个巨大的问题,因为未重新编译的旧类将不会更新其值!如果引用此字段的代码位于不同的jar中,则可能也不会重新编译

涵盖了这个问题

final关键字可用于指定常量值(即在程序执行期间不能更改的值)。但是,可以在程序生命周期内更改的常量不应声明为public final。Java语言规范(JLS)[JLS 2013]允许实现在读取字段的任何编译单元中插入任何公共最终字段的内联值。因此,如果对声明类进行编辑,以便新版本为字段提供不同的值,则读取公共最终字段的编译单元在重新编译之前仍然可以看到旧值。例如,当第三方库更新为最新版本但引用代码未重新编译时,可能会出现此问题

解决方案是将字段
设为私有
,并改用公共静态getter方法

 private static final double PRINT_REDUCTION = 1; //will change often

 public static double getPrintReduction(){
        return PRINT_REDUCTION;
 }
注意,我还将字段大写,这是常量的java编码约定


这一主题以及更多的问题都在

中介绍。“就像一周前我们编写了一些代码,这些代码的位现在召唤出一个恶魔来扰乱我们的常量。或者更准确地说,就像当我们更新常量时,这些更改只反映在它们使用的某些地方。”您是否重新编译了所有代码?或者可能有一些陈旧的.class/.jar文件在某处吗?@JoshuaTaylor这是可能的。我不知道我们的构建系统是如何工作的。然而,由于常量发生了变化,依赖于这些常量的所有其他内容也应该重新构建,对吗?请注意,这些问题似乎偶尔在清理和构建(在NetBeans中)之后仍然存在。很难说,因为问题不稳定。我猜类路径中有旧的JAR/类。@Paul注意到,我们使用的常量(在给定的情况下)是双精度的,在另一种情况下是字符串。这两个类都是原语-我认为链接的答案不适用于原语。@realponsignist好吧,至少这是一种可能的失败方法,尽管我仍然想知道为什么旧类没有得到重建。我应该提到常量和对它的两个引用是同一个项目的一部分,并编译到同一个jar文件中。您引用的文本似乎在讨论jar文件之间的引用,尽管有点不清楚。考虑:
读取公共final字段的编译单元在重新编译之前仍然可以看到旧值。因为这两个类都是同一个项目的一部分,所以“清洁”和“建筑”应该同时更新它们。我们有一个完整的类“constants.java”。这是标准做法,对吗?在那里更新常量通常会在整个项目中生效。您提到过,这种问题有时会在生产中发生。类路径中是否也有旧版本的类?同样值得更改您的
Constants.java
类,以使用我解释的解决方案,看看问题是否仍然存在,是否有可能解决它。如果问题仍然存在或变得更糟,我可能会在更严格的尝试中包含该解决方案