É 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 Enum
próprio.
Como você pode ver, o inicializador estático acessa até o private
campo aliases
. É importante entender que o static
bloco já tem acesso às Enum
instâncias de valor (por exemplo ENGLISH
). Isso ocorre porque a ordem de inicialização e execução no caso de Enum
tipos , como se os static private
campos tivessem sido inicializados com instâncias antes dos static
blocos serem chamados:
- As
Enum
constantes 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)