I found a bug in Java Puzzlers VI - can someone explain it?
Take a look at this java puzzles vid by Josh Bloch and William Pugh, around time index 0:25:00-0:33:00.
One of the speakers says that if you use lowercase boolean
instead of Boolean
, then LIVING
will be treated as a true "compile time constant", and it no longer matters when it is initialized.
Well, this is all fine开发者_运维技巧 and dandy, but, take a look at what happens when you revert to the original order between the static init and the constructor, and then follow it up by a simple "Extract Method" operation. These two programs print different outputs:
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
}
}
And with the refactored returnTrue()
method
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
}
}
Why does extracting the returnTrue() method change the program output in this case?
The key to the behavior that you're observing is notion of "constant variable." This oxymoron is defined in JLS 4.12.4 as a variable of primitive type or type String that is final and initialized with a compile-time constant expression. In JLS 13.1, it says that references to constant fields are resolved at compile time to the constant values they denote (i.e., they're inlined). The puzzle in the video relies on the fact that a Boolean is neither a primitive nor a String. Your variant relies on the fact that invoking a method (returnTrue) in an expression prevents it from being a compile-time constant expression. Either way, LIVING is not a constant variable and the program displays the counterintuitive behavior.
Puzzle 93 in Java Puzzlers ("Class Warfare") is related, and even more surprising.
In the second case LIVING
is initialized by the runtime expression, therefore it's not a compile-time constant any more, and its value is false
at the time when ELVIS
is constructed.
精彩评论