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 ?

Was it helpful?

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);   
} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top