java - 我在 Java Puzzlers VI 中发现了一个错误 - 有人可以解释一下吗?

标签 java

看看这个java puzzles vid作者:Josh Bloch 和 William Pugh,时间索引 0:25:00-0:33:00 左右。

一位发言者说,如果你使用小写的boolean而不是Boolean,那么LIVING将被视为真正的“编译时间”常量”,初始化时就不再重要了。

好吧,这一切都很好,但是,看看当你恢复到静态 init 和构造函数之间的原始顺序时会发生什么,然后通过一个简单的“提取方法”操作来跟进它。这两个程序打印不同的输出:

public class Elvis {
    private static final Elvis ELVIS = new Elvis();

    private Elvis () {}
    private static final boolean LIVING = true;
    private final boolean alive = LIVING;
    private final boolean lives () {return alive;}

    public static void main(String[] args) {
        System.out.println(ELVIS.lives()); // prints true
    }
}

并且使用重构的 returnTrue() 方法

public class Elvis {
    private static final Elvis ELVIS = new Elvis();

    private Elvis () {}
    private static final boolean LIVING = returnTrue();

    private static boolean returnTrue() {
        return true;
    }

    private final boolean alive = LIVING;
    private final boolean lives () {return alive;}

    public static void main(String[] args) {
        System.out.println(ELVIS.lives()); // prints false
    }
}

为什么在这种情况下提取 returnTrue() 方法会改变程序输出?

最佳答案

您观察到的行为的关键是“常量变量”的概念。这个矛盾的定义在 JLS 4.12.4作为原始类型或 String 类型的变量,它是 final 并使用编译时常量表达式进行初始化。在 JLS 13.1 ,它表示对常量字段的引用在编译时解析为它们表示的常量值(即,它们是内联的)。视频中的谜题依赖于 Boolean 既不是原语也不是 String 的事实。您的变体依赖于这样一个事实,即在表达式中调用方法 (returnTrue) 会阻止它成为编译时常量表达式。无论哪种方式,LIVING 都不是一个常量变量,并且程序会显示违反直觉的行为。

Java Puzzlers(“Class Warfare”)中的 Puzzle 93 是相关的,甚至更令人惊讶。

关于java - 我在 Java Puzzlers VI 中发现了一个错误 - 有人可以解释一下吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4607523/

相关文章:

java - Spring 应用程序抛出错误且 WAR 未构建

java - 如何比较包含相同字符的 2 个字符串

java - 使用 SAAJ 从 keystore 中选择特定的客户端证书

neo4j - 为什么 Neo4j 创建 Node[0]?

java - 使用未签名的 Java 小程序从另一个域获取源代码

Java TCP 客户端/服务器

java.lang.IllegalStateException : Trying to requery an already closed cursor error 错误

Java程序在eclipse中执行但不在终端中执行

java - 属性或枚举或静态最终

Java:用于更新不共享相同引用的所有相等对象(在相同上下文中)的模式