Quando ocorre a inicialização da classe estática?

110

Quando os campos estáticos são inicializados? Se eu nunca instanciar uma classe, mas acessar um campo estático, TODOS os blocos estáticos e métodos estáticos privados usados ​​para instanciar campos estáticos privados são chamados (em ordem) naquele instante?

E se eu chamar um método estático? Ele também executa todos os blocos estáticos? Antes do método?

Tony R
fonte
Semelhante para blocos inicializadores estáticos: stackoverflow.com/questions/2007666/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respostas:

156

A inicialização estática de uma classe normalmente acontece imediatamente antes da primeira vez que um dos seguintes eventos ocorre:

  • uma instância da classe é criada,
  • um método estático da classe é invocado,
  • um campo estático da classe é atribuído,
  • um campo estático não constante é usado, ou
  • para uma classe de nível superior, uma instrução assert aninhada lexicamente na classe é executada 1 .

Consulte JLS 12.4.1 .

Também é possível forçar a inicialização de uma classe (se ainda não tiver inicializado) usando Class.forName(fqn, true, classLoader)ou a forma abreviadaClass.forName(fqn)


1 - O ponto final estava presente no JLS para Java 6 até Java 8, mas aparentemente foi um erro na especificação. Finalmente foi corrigido no Java 9 JLS: veja o código-fonte .

Stephen C
fonte
9
Porém, existe uma armadilha comum. Primitivos Stringes são substituídos e não referenciados. Se você fizer referência a um class Other { public static final int VAL = 10; }de alguma classe MyClass { private int = Other.VAL; }, a classe Othernão será carregada. Em vez disso, o compilador simplesmente substituirá o campo final no momento da compilação.
Rafael Winterhalter
6
@RafaelWinterhalter - sim ... esse é o caso de campo estático constante .
Stephen C
2
@RafaelWinterhalter, isso não é verdade para todas as primitivas ou Stringvariáveis 'finais estáticas' , apenas aquelas inicializadas por uma expressão constante.
Lew Bloch
1
Sim, e o campo nem precisa ser staticenquanto isso for um caso comum.
Rafael Winterhalter
1
É a mesma linguagem de programação. Sim.
Stephen C
14

Os campos estáticos são inicializados durante a inicialização "fase" de do carregamento da classe (carregamento, vinculação e inicialização) que inclui inicializadores estáticos e inicializações de seus campos estáticos. Os inicializadores estáticos são executados em uma ordem textual conforme definido na classe.

Considere o exemplo:

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

O Test.b é impresso nullporque, quando o sayHellofoi chamado no escopo estático, a variável estática anão foi inicializada.

Naikus
fonte
6
Estritamente falando, a inicialização não é uma "fase" de carregamento de classe. Na verdade, algumas classes podem ser carregadas, mas nunca inicializadas se o aplicativo não fizer uso delas.
Stephen C de
@Stephen C Você está certo, usei por falta de um termo melhor, talvez eu vá citá-lo.
naikus
@StephenC isso significa que enquanto o carregamento da classe ocorre, ele atribui memória a variáveis ​​estáticas (& métodos), mas essas variáveis ​​estáticas não são inicializadas com valores fornecidos no código? porque aqui parece que quando b-> sayHello () -> a, 'a' está na memória, mas o valor para ele ainda não foi atribuído.
Shabbir Essaji
Basicamente, sim.
Stephen C
1

Sim, todos os inicializadores estáticos são executados antes de você acessar a classe pela primeira vez. Se fosse de outra forma, eu chamaria de bug.

Nikita Rybak
fonte
Existem maneiras de se referir a uma classe sem inicializá-la.
Lew Bloch