¿Cuándo ocurre la inicialización de la clase estática?

110

¿Cuándo se inicializan los campos estáticos? Si nunca creo una instancia de una clase, pero accedo a un campo estático, ¿TODOS los bloques estáticos y los métodos estáticos privados utilizados para instanciar los campos estáticos privados se llaman (en orden) en ese instante?

¿Qué pasa si llamo a un método estático? ¿También ejecuta todos los bloques estáticos? ¿Antes del método?

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

Respuestas:

156

La inicialización estática de una clase normalmente ocurre inmediatamente antes de la primera vez que ocurre uno de los siguientes eventos:

  • se crea una instancia de la clase,
  • se invoca un método estático de la clase,
  • se asigna un campo estático de la clase,
  • se utiliza un campo estático no constante, o
  • para una clase de nivel superior, se ejecuta una declaración de aserción anidada léxicamente dentro de la clase 1 .

Consulte JLS 12.4.1 .

También es posible forzar la inicialización de una clase (si aún no se ha inicializado) usando Class.forName(fqn, true, classLoader)o la forma cortaClass.forName(fqn)


1 - La viñeta final estaba presente en el JLS para Java 6 a Java 8, pero aparentemente fue un error en la especificación. Finalmente se corrigió en Java 9 JLS: ver fuente .

Stephen C
fuente
9
Sin embargo, existe un error común. Los primitivos y Strings están sustituidos y no se hace referencia. Si hace referencia a una class Other { public static final int VAL = 10; }de alguna clase MyClass { private int = Other.VAL; }, la clase Otherno se cargará. En cambio, el compilador simplemente sustituirá el campo final en el momento de la compilación.
Rafael Winterhalter
6
@RafaelWinterhalter - sí ... ese es el caso de campo estático constante .
Stephen C
2
@RafaelWinterhalter, esto no es cierto para todas las primitivas o Stringvariables 'estáticas finales' , solo las inicializadas por una expresión constante.
Lew Bloch
1
Sí, y el campo ni siquiera necesita estarlo staticmientras este es un caso común.
Rafael Winterhalter
1
Es el mismo lenguaje de programación. Si.
Stephen C
14

Los campos estáticos se inicializan durante la "fase" de inicialización de la carga de clases (carga, vinculación e inicialización) que incluye inicializadores estáticos e inicializaciones de sus campos estáticos. Los inicializadores estáticos se ejecutan en un orden textual como se define en la clase.

Considere el ejemplo:

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"
    }
}

Test.b se imprime nullporque cuando sayHellose llamó en el ámbito estático, la variable estática ano se inicializó.

naikus
fuente
6
Estrictamente hablando, la inicialización no es una "fase" de carga de clases. De hecho, algunas clases pueden cargarse pero nunca inicializarse si la aplicación no las utiliza.
Stephen C
@Stephen C Tienes razón, lo usé por falta de un término mejor, tal vez lo cite.
naikus
@StephenC, ¿eso significa que mientras se lleva a cabo la carga de la clase, asigna memoria a las variables estáticas (y métodos) pero esas variables estáticas no se inicializan con los valores proporcionados en el código? porque aquí parece que cuando b-> sayHello () -> a, 'a' está en la memoria pero aún no se le ha asignado un valor.
Shabbir Essaji
Básicamente sí.
Stephen C
1

Sí, todos los inicializadores estáticos se ejecutan antes de acceder a la clase por primera vez. Si fuera de otra manera, lo llamaría error.

Nikita Rybak
fuente
Hay formas de hacer referencia a una clase sin inicializarla.
Lew Bloch