导入的 java 类中的公共静态最终变量
Posted
技术标签:
【中文标题】导入的 java 类中的公共静态最终变量【英文标题】:public static final variable in an imported java class 【发布时间】:2010-12-14 03:59:32 【问题描述】:我在工作场所碰巧遇到了 Java 代码。场景如下:有 2 个类 - ClassA
和 ClassB
。
ClassA
里面只有 4 个公共静态最终字符串值。它的目的是使用像ClassA.variable
这样的值(不要问我为什么,这不是我的代码)。
ClassB
导入 ClassA
。我编辑了ClassA
中的字符串值并编译了它。当我运行ClassB
时,我可以看到它使用的是旧值,而不是新值。我必须重新编译 ClassB
以使其使用来自 ClassA
的新值! (我不得不重新编译导入ClassA
的其他类!)
这仅仅是因为 JDK 1.6 还是我早该知道要重新编译 ClassB
!开导我。 :)
【问题讨论】:
【参考方案1】:如果类ClassA
中的final
变量的值恰好是编译时常量,编译器可能已使用ClassA
将它们内联到类中,而不是生成运行时引用。我想,这就是你描述的情况。
例子:
public class Flags
public static final int FOO = 1;
public static final int BAR = 2;
public class Consumer
public static void main(String[] args)
System.out.println(Flags.FOO);
在此示例中,编译器可能会将FOO
的值合并到为Consumer
生成的代码中,而不是生成等效的运行时引用。如果以后FOO
的值发生变化,您必须重新编译Consumer
才能让它使用新值。
这是一种优化,在编译程序的效率和速度方面有一些优势。例如,内联值可能会进一步优化使用它的表达式,例如:
int x = Flags.FOO * 10;
在此示例中,内联值(此处为:1)使编译器能够注意到乘法没有区别,并且可以一起省略。
【讨论】:
那么,你是说 public static final 是编译时间常数吗?不知道。以为它只是一个常数,不能在运行时修改!感谢您的帮助。 好答案。如果您想查看变量是否被内联,您可以使用 javap 查看类是如何编译的,例如“javap -c 标志”。【参考方案2】:这是一个二进制兼容性问题。对常量字段的引用在编译时解析。您看到的行为是正确的;如果更改 A 类中的值,则必须重新编译客户端(B 类)。为避免此类问题,请考虑使用 Java 5.0 版中引入的枚举类型添加常量。
【讨论】:
【参考方案3】:假设 ClassA 如下所示:
public class ClassA
public static final int FOO = 1;
public static final int BAR = 2;
如果您重新编译它,ClassB 将继续使用旧值。我想这可能取决于编译器,但我认为这是典型的行为。如果您不想每次 ClassA 中的常量更改时都重新编译 ClassB,则必须执行以下操作:
public class ClassA
public static final int FOO = CONST(1);
public static final int BAR = CONST(2);
public static int CONST(int i) return i;
因为现在 javac 不愿意内联常量。相反,它会在 ClassA 的静态初始化程序运行时调用 CONST(int) 方法。
【讨论】:
【参考方案4】:你为什么要单独编译这些类?
使用 maven 或 ant 之类的构建系统,或者让您的 IDE 来做。
唯一安全的做法是重新编译依赖于已更改的 java 类的每个 java,直到重新编译所有可能影响的类。
【讨论】:
其中一个或其他类可能不在您的控制之下。【参考方案5】:如果您不使用开关中的值,您可以这样做:
public class A
public static final int FOO;
public static final String BAR;
static
FOO = 42;
BAR = "Hello, World!";
那么编译器将不再对正在使用它们的其他类中的值进行硬编码。
【讨论】:
以上是关于导入的 java 类中的公共静态最终变量的主要内容,如果未能解决你的问题,请参考以下文章