É um equívoco comum pensar que um bloco estático tem apenas acesso a campos estáticos. Para isso, gostaria de mostrar abaixo um código que frequentemente uso em projetos da vida real (copiado parcialmente de outra resposta em um contexto ligeiramente diferente):
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);
}
}
Aqui, o inicializador é usado para manter um índice ( ALIAS_MAP), para mapear um conjunto de aliases de volta ao tipo de enumeração original. Ele é planejado como uma extensão do método valueOf interno fornecido pelo Enumpróprio.
Como você pode ver, o inicializador estático acessa até o privatecampo aliases. É importante entender que o staticbloco já tem acesso às Enuminstâncias de valor (por exemplo ENGLISH). Isso ocorre porque a ordem de inicialização e execução no caso de Enumtipos , como se os static privatecampos tivessem sido inicializados com instâncias antes dos staticblocos serem chamados:
- As
Enumconstantes que são campos estáticos implícitos. Isso requer que o construtor Enum e os blocos de instância e a inicialização da instância ocorram primeiro também.
static bloco e inicialização de campos estáticos na ordem da ocorrência.
staticÉ importante observar essa inicialização fora de ordem (construtor antes do bloco). Isso também acontece quando inicializamos campos estáticos com as instâncias de forma semelhante a um Singleton (simplificações feitas):
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();
}
}
O que vemos é a seguinte saída:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
Claro é que a inicialização estática realmente pode acontecer antes do construtor e mesmo depois:
O simples acesso ao Foo no método principal faz com que a classe seja carregada e a inicialização estática inicie. Mas, como parte da inicialização estática, chamamos novamente os construtores para os campos estáticos, após o que retoma a inicialização estática e conclui o construtor chamado de dentro do método principal. Situação bastante complexa para a qual espero que na codificação normal não tenhamos que lidar.
Para mais informações, consulte o livro " Java eficaz ".
{...}vsstatic {...}. (caso em que Jon Skeet definitivamente respondeu à sua maneira melhor pergunta)