Quando as variables ​​estáticas são inicializadas?

Eu estou querendo saber quando variables ​​estáticas são inicializadas para seus valores padrão. É correto que, quando uma class é carregada, as variables ​​estáticas são criadas (alocadas) e, em seguida, as inicializações e as inicializações estáticas nas declarações são executadas? Em que ponto os valores padrão são fornecidos? Isso leva ao problema da referência futura.

Também por favor, se você pode explicar isso em referência à pergunta feita em Por que os campos estáticos não são inicializados no tempo? e especialmente a resposta dada por Kevin Brock no mesmo site. Eu não consigo entender o terceiro ponto.

  • É uma variável que pertence à class e não ao object (instância)
  • Variáveis ​​estáticas são inicializadas apenas uma vez, no início da execução.
  • Essas variables ​​serão inicializadas primeiro, antes da boot de quaisquer variables ​​de instância
  • Uma única cópia a ser compartilhada por todas as instâncias da class
  • Uma variável estática pode ser acessada diretamente pelo nome da class e não precisa de nenhum object. Veja Métodos estáticos de variables ​​Java .

As variables ​​de instância e de class (estáticas) são inicializadas automaticamente para os valores padrão padrão se você não as inicializar propositalmente. Embora as variables ​​locais não sejam inicializadas automaticamente, não é possível compilar um programa que falhe ao inicializar uma variável local ou atribuir um valor a essa variável local antes de ela ser usada.

O que o compilador realmente faz é produzir internamente uma rotina de boot de class única que combina todos os inicializadores de variables ​​estáticas e todos os blocos de código de boot estáticos, na ordem em que aparecem na declaração de class. Este procedimento de boot única é executado automaticamente, apenas uma vez, quando a class é carregada pela primeira vez.

No caso de classs internas , elas não podem ter campos estáticos

Uma class interna é uma class aninhada que não é declarada de maneira explícita ou implícita static .

Classes internas não podem declarar inicializadores estáticos (§8.7) ou interfaces de membro …

Classes internas não podem declarar membros estáticos, a menos que sejam variables ​​constantes …

Veja JLS 8.1.3 Classes Internas e Instâncias de Inclusão

final campos final em Java podem ser inicializados separadamente de seu local de declaração, o que, no entanto, não pode ser aplicável a campos static final . Veja o exemplo abaixo.

 final class Demo { private final int x; private static final int z; //must be initialized here. static { z = 10; //It can be initialized here. } public Demo(int x) { this.x=x; //This is possible. //z=15; compiler-error - can not assign a value to a final variable z } } 

Isso ocorre porque há apenas uma cópia das variables static associadas ao tipo, em vez de uma associada a cada instância do tipo, como com variables ​​de instância e se tentarmos inicializar z do tipo static final dentro do construtor, ele tentará reinicialize o campo de tipo static final z porque o construtor é executado em cada instanciação da class que não deve ocorrer em campos final estáticos.

Vejo:

  • JLS 8.7, Inicializadores Estáticos
  • JLS 12.2, Carregamento de Classes e Interfaces
  • JLS 12.4, Inicialização de Classes e Interfaces

O último em particular fornece etapas de boot detalhadas que soletram quando variables ​​estáticas são inicializadas e em que ordem (com a ressalva de que as variables ​​de class final e os campos de interface que são constantes de tempo de compilation são inicializados primeiro).

Não tenho certeza de qual é a sua pergunta específica sobre o ponto 3 (supondo que você quer dizer o nested?). A sequência detalhada indica que isso seria uma solicitação de boot recursiva, portanto, continuará a boot.

Campos estáticos são inicializados quando a class é carregada pelo carregador de classs. Valores padrão são atribuídos neste momento. Isso é feito na ordem em que aparecem no código-fonte.

A ordem de boot é:

  1. Blocos de boot estática
  2. Blocos de boot de instâncias
  3. Construtores

Os detalhes do processo são explicados no documento de especificação da JVM.

variável estática

  • É uma variável que pertence à class e não ao object (instância)
  • As variables ​​estáticas são inicializadas apenas uma vez, no início da execução (quando o Classloader carrega a class pela primeira vez).
  • Essas variables ​​serão inicializadas primeiro, antes da boot de quaisquer variables ​​de instância
  • Uma única cópia a ser compartilhada por todas as instâncias da class
  • Uma variável estática pode ser acessada diretamente pelo nome da class e não precisa de nenhum object

Começando com o código da outra pergunta:

 class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); // will print null once } } 

Uma referência a essa class iniciará a boot. Primeiro, a turma será marcada como inicializada. Em seguida, o primeiro campo estático será inicializado com uma nova instância de MyClass (). Note que myClass recebe imediatamente uma referência a uma instância MyClass em branco . O espaço está lá, mas todos os valores são nulos. O construtor agora é executado e imprime obj , que é nulo.

Agora, voltando a inicializar a class: obj é feito uma referência a um novo object real, e nós terminamos.

Se isso foi desencadeado por uma declaração como: MyClass mc = new MyClass(); espaço para uma nova instância MyClass é novamente alocado (e a referência é colocada em mc ). O construtor é novamente executado e novamente imprime obj , que agora não é nulo.

O verdadeiro truque aqui é que quando você usa new , como em WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii recebe imediatamente uma referência a um pouco de memory nula. A JVM então irá inicializar os valores e executar o construtor. Mas se você de alguma forma referenciar o weii antes de fazer isso – referenciando-o a partir de outro thread ou ou referenciando a partir da boot da class, por exemplo – você está olhando para uma instância de class preenchida com valores nulos.

A variável estática pode ser inicializada das três maneiras a seguir, a seguir, escolha qualquer um que você goste

  1. você pode inicializá-lo no momento da declaração
  2. ou você pode fazer fazendo bloco estático, por exemplo: *

    static {// o código que for necessário para a boot vai aqui}

*

  1. Existe uma alternativa aos blocos estáticos – você pode escrever um método estático privado

 class name { public static varType myVar = initializeVar(); private static varType initializeVar() { // initialization code goes here } }