Порядок выполнения статических блоков в типе Enum w.r.t для конструктора

Это от эффективной 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);
  }

Обратите внимание, что константы операции помещаются на карту stringToEnum из статического блока, который запускается после создания констант. Пытаясь заставить каждую константу вставлять себя в карту из своих собственных конструктор вызовет ошибку компиляции. Это хорошая вещь, потому что это вызовет исключение NullPointerException, если оно будет законным. Enum конструкторам arent разрешен доступ к статическим полям enums, кроме полей постоянной времени компиляции. Это ограничение необходимо поскольку эти статические поля еще не были инициализированы, когда выполняются конструкторы.

Мой вопрос касается линии:

"Обратите внимание, что константы операции помещаются в карту stringToEnum из статического блока, который запускается после создания констант".

Я думал, что статический блок запускается до запуска конструктора. Фактически они выполняются во время загрузки класса.

Что мне здесь не хватает?

Ответ 1

Я понимаю ваш вопрос как: почему существует гарантия того, что константы перечисления будут инициализированы до запуска статического блока. Ответ указан в JLS, а конкретный пример приведен в # 8.9.2.1, со следующим объяснением:

статическая инициализация происходит сверху вниз.

а константы перечисления неявно окончательно статичны и объявляются перед блоком статического инициализатора.

ИЗМЕНИТЬ

Поведение не отличается от обычного класса. Приведенный ниже код печатает:

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");
    }    
}

Ответ 2

Operation Константы - это статические поля, созданные в статическом блоке в появляющемся порядке.

static { 
    // instantiate enum instances here
    ...
    // Initialize map from constant name to enum constant     
    for (Operation op : values())       
       stringToEnum.put(op.toString(), op);   
} 

Ответ 3

Блоки static выполняются в порядке появления (вы можете иметь несколько статических блоков), когда загрузчик классов загружает класс, например. он запускается перед конструктором.