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 Enum
siebie.
Jak widać, statyczny inicjalizator ma dostęp nawet do private
pola aliases
. Ważne jest, aby zrozumieć, że static
blok ma już dostęp do Enum
instancji wartości (np ENGLISH
.). Dzieje się tak, ponieważ kolejność inicjowania i wykonywania w przypadku Enum
typów , tak jakby static private
pola zostały zainicjowane instancjami przed static
wywołaniem bloków:
- Na
Enum
stał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.
static
Należ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)