运行时不反映常量值

4
假设您编译以下两个类。第一个类表示客户端;第二个类是库类。
public class Test{
    public static void main(String[] args) {
        System.out.println(Lib.FIRST + " " +
                           Lib.SECOND + " " +
                           Lib.THIRD);
    }
}


public class Lib{
    private Lib() { }; // Uninstantiable
    public static final String FIRST = "the";
    public static final String SECOND = null;
    public static final String THIRD = "set";
}

输出:

{空集}

现在假设您修改库类如下并重新编译它但不编译客户端程序:

public class Lib{
    private Lib() { }; // Uninstantiable
    public static final String FIRST = "physics";
    public static final String SECOND = "chemistry";
    public static final String THIRD = "biology";
}

打印:

{化学实验套装}

为什么SECOND值发生了变化,但FIRSTTHIRD没有变化?


类路径中有两个“Lib”类吗?你重启了虚拟机吗?你使用的容器是什么? - JustinKSU
2
这段内容直接来自于《Java Puzzlers》一书。包括字符串常量等所有细节都与原书相同。如果你想了解Java的边缘案例,那么这是一本非常好的读物。 - yshavit
1
这个问题确实是从Java Puzzlers(谜题#93)中逐字抄袭的。 - Trevor Freeman
2个回答

7

1
(+1) 好奇...不知道那个。 - NPE
这是被接受的答案,但回应并不够微妙。具体来说,null不是一个常量表达式,因此它不会被内联,而另外两个值则定义了一个常量表达式,因此它们的值被内联(这就是为什么最终打印出来的是“化学实验室”的原因)。 - Trevor Freeman

3
值(即“the”和“set”)在编译时被内联,而null则不会被内联。为了避免这种情况,您可以使用访问器方法。

静态字段不鼓励使用访问器方法,这是个例外情况吗? - kosa
我只是在说,如果他想避免重新编译客户端类本身。 - Bhesh Gurung
不,我完全理解你的意图,我并不是说你说错了什么,别误会。只是想看看你是否知道有没有像这样使用访问器的例外情况。 - kosa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接