Распространено заблуждение, что статический блок имеет доступ только к статическим полям. Для этого я хотел бы показать ниже фрагмент кода, который я довольно часто использую в реальных проектах (частично скопированный из другого ответа в несколько ином контексте):
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);
}
}
Здесь инициализатор используется для поддержки index ( 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 ».
{...}
противstatic {...}
. (в этом случае Джон Скит определенно ответил на ваш вопрос лучше)