latest - java puzzlers traps pitfalls and corner cases(english) 1st edition pdf




I found a bug in Java Puzzlers VI-can someone explain it? (2)

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?


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.


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.





java