Tanto quanto eu entendi, o "bloco de inicialização estática" é usado para definir valores do campo estático, se não puder ser feito em uma linha.
Mas não entendo por que precisamos de um bloco especial para isso. Por exemplo, declaramos um campo como estático (sem uma atribuição de valor). E, em seguida, escreva várias linhas do código que geram e atribuem um valor ao campo estático declarado acima.
Por que precisamos dessas linhas em um bloco especial como static {...}
:?
{...}
vsstatic {...}
. (caso em que Jon Skeet definitivamente respondeu à sua maneira melhor pergunta)Respostas:
O bloco não estático:
É chamado toda vez que uma instância da classe é construída. O bloco estático é chamado apenas uma vez , quando a própria classe é inicializada, não importa quantos objetos desse tipo você crie.
Exemplo:
Isso imprime:
fonte
Se eles não estivessem em um bloco de inicialização estático, onde estariam? Como você declararia uma variável que deveria ser apenas local para fins de inicialização e a distinguiria de um campo? Por exemplo, como você gostaria de escrever:
Se
first
esecond
não estivessem em um bloco, eles pareceriam campos. Se eles estivessem em um bloco sem a suastatic
frente, isso contaria como um bloco de inicialização da instância em vez de um bloco estático de inicialização, portanto, seria executado uma vez por instância construída e não uma vez no total.Agora, nesse caso específico, você pode usar um método estático:
... mas isso não funciona quando há várias variáveis que você deseja atribuir dentro do mesmo bloco ou nenhuma (por exemplo, se você deseja apenas registrar algo - ou talvez inicializar uma biblioteca nativa).
fonte
private static int widgets = 0; static{widgets = 2;}
private static int widgets = 0; static{widgets = 2;}
Descobriu que a atribuição '=' acontece em ordem, o que significa que a colocação '=' primeiro será atribuída primeiro. O exemplo acima vai dar 'widgets' um valor de 2. (PS não sabia que os comentários só pode ser editado em 5 min ...)Aqui está um exemplo:
O código nas seções "estáticas" será executado no tempo de carregamento da classe, antes que quaisquer instâncias da classe sejam construídas (e antes que qualquer método estático seja chamado de outro lugar). Dessa forma, você pode garantir que todos os recursos da classe estejam prontos para uso.
Também é possível ter blocos de inicialização não estáticos. Eles agem como extensões ao conjunto de métodos construtores definidos para a classe. Eles se parecem com blocos inicializadores estáticos, exceto que a palavra-chave "estática" é deixada de lado.
fonte
Também é útil quando você realmente não deseja atribuir o valor a nada, como carregar alguma classe apenas uma vez durante o tempo de execução.
Por exemplo
Ei, há outro benefício, você pode usá-lo para lidar com exceções. Imagine que
getStuff()
aqui lança umException
que realmente pertence a um bloco catch:então um
static
inicializador é útil aqui. Você pode lidar com a exceção lá.Outro exemplo é fazer coisas posteriores que não podem ser feitas durante a atribuição:
Para voltar ao exemplo do driver JDBC, qualquer driver JDBC decente também faz uso do
static
inicializador para se registrar noDriverManager
. Veja também esta e esta resposta.fonte
Eu diria que
static block
é apenas açúcar sintático. Não há nada que você possa fazer com ostatic
bloco e não com mais nada.Para reutilizar alguns exemplos publicados aqui.
Este trecho de código pode ser reescrito sem o uso do
static
inicializador.Método # 1: Com
static
Método # 2: Sem
static
fonte
Existem algumas razões reais para a sua existência:
static final
membros inicializadores cuja inicialização pode gerar uma exceçãostatic final
membros com valores calculadosAs pessoas tendem a usar
static {}
blocos como uma maneira conveniente de inicializar coisas das quais a classe depende dentro do tempo de execução - como garantir que uma determinada classe seja carregada (por exemplo, drivers JDBC). Isso pode ser feito de outras maneiras; no entanto, as duas coisas que mencionei acima só podem ser feitas com uma construção como ostatic {}
bloco.fonte
Você pode executar bits de código uma vez para uma classe antes que um objeto seja construído nos blocos estáticos.
Por exemplo
fonte
É 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):
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 peloEnum
próprio.Como você pode ver, o inicializador estático acessa até o
private
campoaliases
. É importante entender que ostatic
bloco já tem acesso àsEnum
instâncias de valor (por exemploENGLISH
). Isso ocorre porque a ordem de inicialização e execução no caso deEnum
tipos , como se osstatic private
campos tivessem sido inicializados com instâncias antes dosstatic
blocos serem chamados: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):O que vemos é a seguinte saída:
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 ".
fonte
aliases
não significa que o bloco estático possa acessar membros não estáticos.aliases
é acessado através dosLanguage
valores retornados pelovalues()
método / static / . Como você mencionou, o fato de as variáveis enum já estarem disponíveis nesse momento é o bit incomum - membros não estáticos de classes regulares não estariam acessíveis nessa situação.class Foo { static final Foo Inst1; static final Foo Inst2; static{ Inst1 = new Foo("Inst1"); Inst2 = new Foo("Inst2"); } static { System.out.println("Inst1: " + Inst1.member); System.out.println("Inst2: " + Inst2.member); } private final String member; private Foo(String member){ this.member = member; } }
O código acima não é diferente do exemplo enum e ainda permite o acesso de exemplo variável dentro do bloco estáticoEnum
. É a melhor maneira de garantir que estamos apontando para instâncias singulares '- veja aqui . E para você, fiz várias atualizações.Se suas variáveis estáticas precisam ser definidas em tempo de execução, um
static {...}
bloco é muito útil.Por exemplo, se você precisar definir o membro estático para um valor armazenado em um arquivo de configuração ou banco de dados.
Também é útil quando você deseja adicionar valores a um
Map
membro estático, pois não é possível adicionar esses valores na declaração inicial do membro.fonte
Então você tem um campo estático (também é chamado de "variável de classe" porque pertence à classe e não a uma instância da classe; em outras palavras, está associado à classe e não a qualquer objeto) e deseja inicializá-lo. Portanto, se você NÃO quiser criar uma instância dessa classe e manipular esse campo estático, poderá fazê-lo de três maneiras:
1- Apenas inicialize quando você declarar a variável:
2- Tenha um bloco de inicialização estático:
3- Ter um método de classe (método estático) que acessa a variável de classe e a inicializa: esta é a alternativa ao bloco estático acima; você pode escrever um método estático privado:
Agora, por que você usaria o bloco de inicialização estático em vez de métodos estáticos?
Realmente depende do que você precisa em seu programa. Mas você precisa saber que o bloco de inicialização estática é chamado uma vez e a única vantagem do método de classe é que eles podem ser reutilizados posteriormente, se você precisar reinicializar a variável de classe.
digamos que você tenha uma matriz complexa em seu programa. Você inicializa-la (usando para circuito por exemplo) e, em seguida, os valores desta matriz irá mudar ao longo do programa, mas, em seguida, em algum momento você quer reinicializar-lo (voltar ao valor inicial). Nesse caso, você pode chamar o método estático privado. Caso você não precise reinicializar os valores em seu programa, basta usar o bloco estático e não é necessário um método estático, pois você não o utilizará posteriormente no programa.
Nota: os blocos estáticos são chamados na ordem em que aparecem no código.
Exemplo 1:
Exemplo 2:
fonte
Como suplementar, como @Pointy disse
É suposto adicionar
System.loadLibrary("I_am_native_library")
no bloco estático.Ele garantirá que nenhum método nativo seja chamado antes que a biblioteca relacionada seja carregada na memória.
De acordo com loadLibrary da oracle :
Então, inesperadamente, colocar System.loadLibrary não é usado para evitar que a biblioteca seja carregada várias vezes.
fonte
Você primeiro precisa entender que suas próprias classes de aplicativos são instanciadas em
java.class.Class
objetos durante o tempo de execução. É quando seus blocos estáticos são executados. Então você pode realmente fazer isso:e imprimiria "myInt é 1" no console. Observe que eu não instanciei nenhuma classe.
fonte
fonte
O bloco estático é usado para qualquer tecnologia para inicializar o membro de dados estáticos de maneira dinâmica, ou podemos dizer que a inicialização dinâmica do membro estático está sendo usada. O bloco estático está sendo usado .. Por causa da inicialização do membro de dados não estáticos, temos construtor, mas não temos qualquer lugar onde possamos inicializar dinamicamente o membro de dados estáticos
Agora meu int x estático será inicializado dinamicamente .. Quando o compilador for para o Solution.x, ele carregará a Classe de Solução e o bloco estático no tempo de carregamento da classe. Assim, podemos inicializar dinamicamente esse membro de dados estáticos.
}
fonte