ProgramaciónDesarrollador Java Middle/Senior

¿Qué es el orden de inicialización de clases en Java, cómo funciona y a qué puede llevar una comprensión incorrecta del orden de inicialización de miembros estáticos y no estáticos?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

El orden de inicialización de clases en Java (class initialization order) determina en qué secuencia se inicializan los campos, bloques y constructores. En resumen:

  1. Los campos estáticos y los inicializadores estáticos se ejecutan en el orden en que aparecen en la clase, cuando la clase es cargada por la JVM (una vez por clase).
  2. Los campos no estáticos y los inicializadores se ejecutan en el orden en que aparecen CADA vez que se crea una instancia, antes de la llamada al constructor.
  3. El constructor se ejecuta después de la inicialización de todos los campos y bloques.

Ejemplo

class Parent { static { System.out.println("Parent static"); } { System.out.println("Parent init"); } Parent() { System.out.println("Parent constructor"); } } class Child extends Parent { static { System.out.println("Child static"); } { System.out.println("Child init"); } Child() { System.out.println("Child constructor"); } } // new Child() -> ¿qué orden?

La salida será:

  1. Parent static
  2. Child static
  3. Parent init
  4. Parent constructor
  5. Child init
  6. Child constructor

Primero los bloques estáticos de los padres, luego los bloques estáticos de los hijos, y luego los bloques no estáticos y los constructores en orden de herencia.

Pregunta capciosa.

Pregunta: ¿Cuándo se ejecutarán los inicializadores estáticos en la clase:

class Ex {
    static { System.out.println("static"); }
}

— al crear la primera instancia o al primer uso de cualquier método/campo estático?

Respuesta: El inicializador estático se ejecuta al primer acceso a la clase, incluyendo el acceso a cualquier miembro estático (método/campo), y no solo al crear una instancia.

Ejemplos de errores reales debido a la falta de conocimiento de los matices del tema.


Historia

En una aplicación bancaria, el grupo de conexiones estáticas se inicializaba en un bloque estático, pero debido al acceso a un método estático antes de crear la primera instancia, la conexión aún no se había creado. Esto llevó a un NullPointerException al ejecutarse bajo carga.


Historia

El servicio de registro dependía de un campo no estático, que se inicializaba después de la llamada al constructor de la clase base. Los registros se escribían en un registrador nulo, y se perdieron importantes mensajes de error.


Historia

Al agregar un nuevo campo con un valor inicial, el desarrollador lo colocó después del bloque de inicialización: el bloque intentaba usar un campo no inicializado, lo que llevaba a errores durante el arranque de la aplicación y complicadas búsquedas de la causa.