Execution order of of static blocks in an Enum type w.r.t to constructor
Question
This is from Effective Java :
// Implementing a fromString method on an enum type
private static final Map<String, Operation> stringToEnum
= new HashMap<String, Operation>();
static { // Initialize map from constant name to enum constant
for (Operation op : values())
stringToEnum.put(op.toString(), op);
}
// Returns Operation for string, or null if string is invalid
public static Operation fromString(String symbol) {
return stringToEnum.get(symbol);
}
Note that the Operation constants are put into the stringToEnum map from a static block that runs after the constants have been created. Trying to make each constant put itself into the map from its own constructor would cause a compilation error. This is a good thing, because it would cause a NullPointerException if it were legal. Enum constructors aren’t permitted to access the enum’s static fields, except for compile-time constant fields. This restriction is necessary because these static fields have not yet been initialized when the constructors run.
My question is regarding the line :
"Note that the Operation constants are put into the stringToEnum map from a static block that runs after the constants have been created" .
I thought the static block gets executed before the constructor runs. The are actually executed during class load time.
What am I missing here ?
Solution
I understand your question as: why is there a guarantee that the enum constants will be initialised before the static block is run. The answer is given in the JLS, and a specific example is given in #8.9.2.1, with the following explanation:
static initialization occurs top to bottom.
and the enums constants are implicitly final static and are declared before the static initializer block.
EDIT
The behaviour is not different from a normal class. The code below prints:
In constructor: PLUS
PLUS == null MINUS == null
In constructor: MINUS
PLUS != null MINUS == null
In static initialiser
PLUS != null MINUS != null
In constructor: after static
PLUS != null MINUS != null
public class Operation {
private final static Operation PLUS = new Operation("PLUS");
private final static Operation MINUS = new Operation("MINUS");
static {
System.out.println("In static initialiser");
System.out.print("PLUS = " + PLUS);
System.out.println("\tMINUS = " + MINUS);
}
public Operation(String s) {
System.out.println("In constructor: " + s);
System.out.print("PLUS = " + PLUS);
System.out.println("\tMINUS = " + MINUS);
}
public static void main(String[] args) {
Operation afterStatic = new Operation ("after static");
}
}
OTHER TIPS
The static
blocks execute in order of appearance (you can have multiple static blocks), when the class loader loads the class, eg. it runs before the constructor.
Operation
constants are static fields created in the static block in the appearing order.
static {
// instantiate enum instances here
...
// Initialize map from constant name to enum constant
for (Operation op : values())
stringToEnum.put(op.toString(), op);
}