看看Josh Bloch和William Pugh的这个java谜题视频,时间指数0:25:00-0:33:00.
其中一个发言者说,如果你使用小写boolean
而不是Boolean
,那么LIVING
将被视为一个真正的"编译时常量",并且它在初始化时不再重要.
好吧,这一切都很好,但是,看看当你恢复静态初始化和构造函数之间的原始顺序时会发生什么,然后通过一个简单的"提取方法"操作来跟进它.这两个程序打印不同的输出:
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
}
}
Run Code Online (Sandbox Code Playgroud)
并使用重构的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
}
}
Run Code Online (Sandbox Code Playgroud)
为什么在这种情况下提取returnTrue()方法会改变程序输出?
Jos*_*och 47
你所观察到的行为的关键是"常量变量"的概念.这个矛盾在JLS 4.12.4中定义为原始类型或类型String的变量,它是final并用编译时常量表达式初始化.在JLS 13.1中,它表示对常量字段的引用在编译时被解析为它们表示的常量值(即,它们是内联的).视频中的难题依赖于布尔既不是基元也不是字符串的事实.您的变体依赖于以下事实:在表达式中调用方法(returnTrue)会阻止它成为编译时常量表达式.无论哪种方式,LIVING都不是常量变量,程序会显示违反直觉的行为.
Java Puzzlers中的Puzzle 93("Class Warfare")是相关的,甚至更令人惊讶.
归档时间: |
|
查看次数: |
1015 次 |
最近记录: |