Распространено заблуждение, что статический блок имеет доступ только к статическим полям. Для этого я хотел бы показать ниже фрагмент кода, который я довольно часто использую в реальных проектах (частично скопированный из другой ответ в несколько ином контексте):
public enum Language {
ENGLISH("eng", "en", "en_GB", "en_US"),
GERMAN("de", "ge"),
CROATIAN("hr", "cro"),
RUSSIAN("ru"),
BELGIAN("be",";-)");
static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>();
static {
for (Language l:Language.values()) {
// ignoring the case by normalizing to uppercase
ALIAS_MAP.put(l.name().toUpperCase(),l);
for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l);
}
}
static public boolean has(String value) {
// ignoring the case by normalizing to uppercase
return ALIAS_MAP.containsKey(value.toUpper());
}
static public Language fromString(String value) {
if (value == null) throw new NullPointerException("alias null");
Language l = ALIAS_MAP.get(value);
if (l == null) throw new IllegalArgumentException("Not an alias: "+value);
return l;
}
private List<String> aliases;
private Language(String... aliases) {
this.aliases = Arrays.asList(aliases);
}
}
Здесь инициализатор используется для поддержания индекса (ALIAS_MAP
), чтобы отобразить набор псевдонимов обратно в исходный тип перечисления. Он предназначен как расширение встроенного метода valueOf, предоставляемого самим Enum
.
Как видите, статический инициализатор обращается даже к полю private
aliases
. Важно понимать, что блок static
уже имеет доступ к экземплярам значения Enum
(например, ENGLISH
). Это связано с тем, что порядок инициализации и выполнения в случае Enum
типов , как если бы поля static private
были инициализированы с экземплярами до вызова блоков static
:
- Константы
Enum
, которые являются неявными статическими полями. Это требует, чтобы конструктор Enum и блоки экземпляра, а также инициализация экземпляра выполнялись первыми.
static
блок и инициализация статических полей в порядке появления.
Важно отметить эту неправильную инициализацию (конструктор перед static
блоком). Это также происходит, когда мы инициализируем статические поля с экземплярами, аналогичными Singleton (сделаны упрощения):
public class Foo {
static { System.out.println("Static Block 1"); }
public static final Foo FOO = new Foo();
static { System.out.println("Static Block 2"); }
public Foo() { System.out.println("Constructor"); }
static public void main(String p[]) {
System.out.println("In Main");
new Foo();
}
}
Мы видим следующий вывод:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
Понятно, что статическая инициализация действительно может произойти до конструктора и даже после:
Простой доступ к Foo в методе main приводит к загрузке класса и запуску статической инициализации. Но как часть статической инициализации мы снова вызываем конструкторы для статических полей, после чего она возобновляет статическую инициализацию и завершает конструктор, вызываемый из основного метода. Довольно сложная ситуация, для которой я надеюсь, что в нормальном кодировании нам не пришлось бы иметь дело.
Подробнее об этом см. Книгу " Эффективная Java ".