看看这个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/