¿Por qué los campos estáticos no se inicializan a tiempo?

El siguiente código imprime null una vez.

 class MyClass { private static MyClass myClass = new MyClass(); private static final Object obj = new Object(); public MyClass() { System.out.println(obj); } public static void main(String[] args) {} } 

¿Por qué los objetos estáticos no se inicializan antes de que se ejecute el constructor?

Actualizar

Acabo de copiar este progtwig de ejemplo sin prestar atención, pensé que estábamos hablando de 2 campos Object, ahora vi que el primero es un campo MyClass ..: /

Porque la estática se inicializa en el orden que se les da en el código fuente.

Mira esto:

 class MyClass { private static MyClass myClass = new MyClass(); private static MyClass myClass2 = new MyClass(); public MyClass() { System.out.println(myClass); System.out.println(myClass2); } } 

Eso se imprimirá:

 null null myClassObject null 

EDITAR

Ok, vamos a sacar esto para ser un poco más claros.

  1. Las estadísticas se inicializan una por una en el orden declarado en el código fuente.
  2. Dado que la primera estática se inicializa antes que el rest, durante su inicialización el rest de los campos estáticos son valores nulos o predeterminados.
  3. Durante el inicio de la segunda estática, la primera estática es correcta, pero el rest sigue siendo nula o predeterminada.

¿Está claro?

EDIT 2

Como Varman señaló, la referencia a sí misma será nula mientras se inicializa. Lo cual tiene sentido si lo piensas.

Probemos una forma diferente de explicar esto …

Esta es la secuencia por la que pasa la JVM cuando hace referencia por primera vez a la clase MyClass .

  1. Cargue el código de bytes en la memoria.
  2. La memoria para el almacenamiento estático se borra (cero binario).
  3. Inicializa la clase:
    1. Ejecute cada inicializador estático en el orden en que aparece, esto incluye variables static { ... } y bloques static { ... } .
    2. JVM luego inicializa su variable estática myClass en una nueva instancia de MyClass .
    3. Cuando esto sucede, la JVM nota que MyClass ya está cargado (byte-code) y está en proceso de inicialización , por lo que omite la inicialización.
    4. Asignar memoria en el montón para el objeto.
    5. Ejecutar constructor
    6. Imprima el valor de obj que sigue siendo null (ya que no forma parte de las variables inicializadas de montón y constructor).
    7. Cuando el constructor finaliza, ejecuta el siguiente inicializador estático que establece obj en una nueva instancia de Object .
  4. Inicialización de clase hecha A partir de este punto, todas las llamadas al constructor se comportarán de la forma que suponga / espere, es decir, obj no sería null sino una referencia a una instancia de Object .

Recuerde que Java especifica que a una variable final se le asigna un valor una vez. No se garantiza que se le asigne un valor cuando el código lo haga referencia a menos que se asegure de que el código lo referencia después de que se le asigne.

Esto no es un error. Esta es la forma definida de manejar el uso de la clase durante su propia inicialización. Si esto no fuera así, entonces la JVM entraría en un ciclo infinito. Vea el paso # 3.3 (si la JVM no omite la inicialización para una clase que está en proceso de inicialización, simplemente la mantendrá inicializada – bucle infinito).

Tenga en cuenta también que todo esto sucede en el mismo hilo que primero hace referencia a la clase. En segundo lugar, la JVM garantiza que la inicialización se completará antes de que cualquier otro subproceso pueda usar esta clase.

Eso es porque Java ejecuta la sección estática para que se declare. En tu caso, la secuencia es

  1. nueva MyClass
  2. Objeto nuevo

Cuando se ejecuta # 1, obj aún no se inicializa, por lo que imprime nulo. Prueba lo siguiente y verás la diferencia:

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

En términos generales, es mejor evitar una construcción así todos juntos. Si está intentando crear un singleton, así es como debería verse ese fragmento de código:

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

esto se debe a que los campos estáticos se inicializaron en el mismo orden que definieron.

@Pyrolistical

dado que la inicial del primer campo estático myclass no está completamente construido … el resultado que obtengo es

null null testInitialize.MyObject@70f9f9d8 null