Powszechnym błędem jest myślenie, że blok statyczny ma dostęp tylko do pól statycznych. W tym celu chciałbym pokazać poniżej fragment kodu, który dość często używam w rzeczywistych projektach (skopiowany częściowo z innej odpowiedzi w nieco innym kontekście):
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);
}
}
W tym przypadku inicjalizator służy do utrzymywania indeksu ( ALIAS_MAP) w celu odwzorowania zestawu aliasów z powrotem na oryginalny typ wyliczenia. Ma to stanowić rozszerzenie wbudowanej metody valueOf dostarczonej przez Enumsiebie.
Jak widać, statyczny inicjalizator ma dostęp nawet do privatepola aliases. Ważne jest, aby zrozumieć, że staticblok ma już dostęp do Enuminstancji wartości (np ENGLISH.). Dzieje się tak, ponieważ kolejność inicjowania i wykonywania w przypadku Enumtypów , tak jakby static privatepola zostały zainicjowane instancjami przed staticwywołaniem bloków:
- Na
Enumstałe, które są ukryte pola statycznego. Wymaga to konstruktora Enum i bloków instancji, a także inicjalizacji instancji w pierwszej kolejności.
static blok i inicjalizacja pól statycznych w kolejności występowania.
staticNależy pamiętać o tej inicjalizacji poza kolejnością (konstruktor przed blokiem). Dzieje się tak również, gdy inicjalizujemy pola statyczne instancjami podobnie jak Singleton (dokonane uproszczenia):
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();
}
}
Widzimy następujące dane wyjściowe:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
Oczywiste jest, że inicjalizacja statyczna może faktycznie nastąpić przed konstruktorem, a nawet po:
Prosty dostęp do Foo w głównej metodzie powoduje załadowanie klasy i rozpoczęcie inicjalizacji statycznej. Ale w ramach inicjalizacji statycznej ponownie wywołujemy konstruktory dla pól statycznych, po czym wznawia się inicjalizację statyczną i kończy konstruktor wywoływany z metody głównej. Raczej złożona sytuacja, w przypadku której mam nadzieję, że przy normalnym kodowaniu nie musielibyśmy się uporać.
Więcej informacji na ten temat można znaleźć w książce „ Skuteczna Java ”.
{...}vsstatic {...}. (w takim przypadku Jon Skeet zdecydowanie lepiej odpowiedział na twoje pytanie)