导入的 java 类中的公共静态最终变量

Posted

技术标签:

【中文标题】导入的 java 类中的公共静态最终变量【英文标题】:public static final variable in an imported java class 【发布时间】:2010-12-14 03:59:32 【问题描述】:

我在工作场所碰巧遇到了 Java 代码。场景如下:有 2 个类 - ClassAClassB

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 类中的公共静态最终变量的主要内容,如果未能解决你的问题,请参考以下文章

Java中的static

为啥接口变量默认是静态的和最终的?

java基础(static---静态方法和静态变量以及静态方法)

java覆盖和隐藏

java 在调试的时候如何查看类中的静态变量值

Kotlin CI 测试期间的静态最终变量初始化(Java 中)不正确