It is common for a class to have constant values defined as class fields (static and final) and then used in instances fields like in code bellow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Initialization { private static final Boolean DONE = Boolean.TRUE; private boolean done = DONE; public boolean isDone() { return done; } public static void main(String... args) { System.out.println("isDone(): " + new Initialization().isDone()); } } |
We all know that static fields are initialized first and then the instance ones, so it is no surprise until now. To be even more clear, I updated the code by adding code blocks with print statements:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Initialization { private static final Boolean DONE; static { System.out.println("setting up DONE"); DONE = Boolean.TRUE; System.out.println("DONE: " + DONE); } private boolean done; { System.out.println("setting up done"); done = DONE; System.out.println("done: " + done); } public boolean isDone() { return done; } public static void main(String... args) { System.out.println("isDone(): " + new Initialization().isDone()); } } |
that displays:
1 2 3 4 5 6 |
setting up DONE DONE: true setting up done done: true isDone(): true |
It is what we all expected so why I bother with posting about such simple things? It is because Elvis lives again. I get into trouble if I add a singleton instance at the beginning of the class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class RecursiveInitialization { private static final RecursiveInitialization TROUBLE = new RecursiveInitialization(); //line 2 private static final Boolean DONE; static { System.out.println("setting up DONE"); DONE = Boolean.TRUE; System.out.println("DONE: " + DONE); } private boolean done; { System.out.println("setting up done"); done = DONE; //line 14 System.out.println("done: " + done); } public boolean isDone() { return done; } public static void main(String... args) { System.out.println("isDone(): " + TROUBLE.isDone()); } } |
The only difference is that we are using that singleton instance so I would expect the same result but instead I get:
1 2 3 4 5 6 |
setting up done Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.NullPointerException at RecursiveInitialization.<init>(RecursiveInitialization.java:14) at RecursiveInitialization.<clinit>(RecursiveInitialization.java:2) |
In order to understand what happens we need to read When Initialization Occurs:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
- T is a class and an instance of T is created.
- T is a class and a static method declared by T is invoked.
and Detailed Initialization Procedure, step 3:
For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation. The procedure for initializing C is then as follows:
- Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC.
- If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this step.
- If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally.
After reading above sections, my understanding is that the following happens:
- RecursiveInitialization class is initialized because its main method is called.
- TROUBLE is a static field so it is initialized.
- TROUBLE is an instance of RecursiveInitialization so RecursiveInitialization should be initialized. There is already a class initialization in progress, so it completes normally. Instance field done is initialized with unboxed value of DONE, which is null and we receive that NullPointerException.
A simple fix is to move the singleton declaration and instantion after the static block:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class RecursiveInitialization { private static final Boolean DONE; static { System.out.println("setting up DONE"); DONE = Boolean.TRUE; System.out.println("DONE: " + DONE); } private static final RecursiveInitialization TROUBLE = new RecursiveInitialization(); private boolean done; { System.out.println("setting up done"); done = DONE; System.out.println("done: " + done); } public boolean isDone() { return done; } public static void main(String... args) { System.out.println("isDone(): " + TROUBLE.isDone()); } } |
and everything gets back to normal:
1 2 3 4 5 6 |
setting up DONE DONE: true setting up done done: true isDone(): true |
If this subjects interests you and you need more information about it, here is another example.
After seeing what can happen if I don’t pay attention to initialization details, I will be more careful in such situations.