poner - ¿Los campos se inicializan antes de que el código de constructor se ejecute en Java?
set border java (4)
El orden correcto de inicialización es:
- Inicializadores de variables estáticas y bloques de inicialización estáticos, en orden textual, si la clase no se ha inicializado previamente.
- La llamada a super () en el constructor, ya sea explícita o implícita.
- Instaladores de variables de instancia y bloques de inicialización de instancia, en orden textual.
- El resto del cuerpo del constructor después de super ().
Consulte las secciones §2.17.5-6 de la Especificación de máquina virtual de Java .
¿Alguien puede explicar el resultado del siguiente programa? Pensé que los constructores se inicializan antes de las variables de instancia. Así que esperaba que la salida fuera "XZYY".
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
La secuencia de inicialización se especifica en JLS 12.5:
1. Primero, la memoria se asigna para el nuevo objeto
2. Luego todas las variables de instancia en el objeto (incluidas las definidas en esta clase y todas sus superclases) se inicializan a sus valores predeterminados
3.Finalmente, se llama al constructor.
Para aclarar los malentendidos con estática, simplemente me referiré a este pequeño fragmento de código:
public class Foo {
{ System.out.println("Instance Block 1"); }
static { System.out.println("Static Block 1"); }
public static final Foo FOO = new Foo();
{ System.out.println("Instance Block 2"); }
static { System.out.println("Static Block 2 (Weird!!)"); }
public Foo() { System.out.println("Constructor"); }
static public void main(String p[]) {
System.out.println("In Main");
new Foo();
}
}
Sorpresa es que la salida es la siguiente:
Static Block 1
Instance Block 1
Instance Block 2
Constructor
Static Block 2 (Weird!!)
In Main
Instance Block 1
Instance Block 2
Constructor
Tenga en cuenta que tenemos un static {}
que se llama después de dos instancias {}
. esto sucede porque lanzamos el constructor en el medio, intercalando el orden de ejecución la primera vez que se llama al constructor.
Descubrí esto cuando estaba trabajando en esta respuesta: https://.com/a/30837385/744133 .
Básicamente observamos que esto suceda:
Durante la primera vez que se inicializa un objeto, Inicialice el objeto actual para la inicialización estática y de la instancia entremezclada según el orden de aparición
Para todas las siguientes inicializaciones, solo realice la inicialización de la instancia en el orden de aparición, ya que la inicialización estática ya ocurrió.
Necesito investigar cómo la mezcla de herencia, y las llamadas explícitas e implícitas a super y esto afectarán esto, y actualizaré con los hallazgos. Es probable que sea similar a las otras respuestas suministradas, excepto que se equivocaron con la inicialización estática.
Si nos fijamos en la versión descompilada del archivo de clase
class X {
Y b;
X() {
b = new Y();
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y;
Z() {
y = new Y();
System.out.print("Z");
}
public static void main(String args[]) {
new Z();
}
}
Puede encontrar que la variable de instancia y
se mueve dentro del constructor, por lo que la secuencia de ejecución es la siguiente
- Llamar al constructor de
Z
- Activa el constructor predeterminado de
X
- Primera línea del constructor
X
new Y()
llamadanew Y()
. - Imprimir Y
- Imprimir X
- Llamar a la primera línea en el constructor Z
new Y()
- Imprimir
Y
- Imprimir Z
Todas las variables de instancia se inicializan mediante el uso de declaraciones de constructor.