Порядок выполнения статических блоков в типе Enum по отношению к конструктору
Это из эффективной 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);
}
Обратите внимание, что константы Operation помещаются в карту stringToEnum из статического блока, который запускается после создания констант. Попытка заставить каждую константу поместить себя в карту из своего собственного конструктора приведет к ошибке компиляции. Это хорошая вещь, потому что это вызвало бы исключение NullPointerException, если бы оно было законным. Конструкторам enum не разрешен доступ к статическим полям enum, за исключением полей констант времени компиляции. Это ограничение необходимо, потому что эти статические поля еще не были инициализированы при запуске конструкторов.
Мой вопрос касается линии:
Msgstr "Обратите внимание, что константы Operation помещаются в карту stringToEnum из статического блока, который запускается после создания констант" .
Я думал, что статический блок исполняется до запуска конструктора. Фактически выполняются во время загрузки класса.
Что мне здесь не хватает?
3 ответа
Я понимаю ваш вопрос как: почему есть гарантия, что константы enum будут инициализированы до запуска статического блока. Ответ дан в 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");
}
}
static
блоки выполняются в порядке появления (у вас может быть несколько статических блоков), когда загрузчик класса загружает класс, например. он работает перед конструктором.
Operation
константы - это статические поля, созданные в статическом блоке в порядке появления.
static {
// instantiate enum instances here
...
// Initialize map from constant name to enum constant
for (Operation op : values())
stringToEnum.put(op.toString(), op);
}