2010-01-05 11 views
81

Digamos que un proyecto contiene varias clases, cada una de las cuales tiene un bloque de inicializador estático. ¿En qué orden se ejecutan esos bloques? Sé que dentro de una clase, dichos bloques se ejecutan en el orden en que aparecen en el código. He leído que es igual en todas las clases, pero un código de muestra que escribí no está de acuerdo con eso. He utilizado este código:¿En qué orden se ejecutan los bloques de inicializador estático/instancia en Java?

package pkg; 

public class LoadTest { 
    public static void main(String[] args) { 
     System.out.println("START"); 
     new Child(); 
     System.out.println("END"); 
    } 
} 

class Parent extends Grandparent { 
    // Instance init block 
    { 
     System.out.println("instance - parent"); 
    } 

    // Constructor 
    public Parent() { 
     System.out.println("constructor - parent"); 
    } 

    // Static init block 
    static { 
     System.out.println("static - parent"); 
    } 
} 

class Grandparent { 
    // Static init block 
    static { 
     System.out.println("static - grandparent"); 
    } 

    // Instance init block 
    { 
     System.out.println("instance - grandparent"); 
    } 

    // Constructor 
    public Grandparent() { 
     System.out.println("constructor - grandparent"); 
    } 
} 

class Child extends Parent { 
    // Constructor 
    public Child() { 
     System.out.println("constructor - child"); 
    } 

    // Static init block 
    static { 
     System.out.println("static - child"); 
    } 

    // Instance init block 
    { 
     System.out.println("instance - child"); 
    } 
} 

y obtuve este resultado:

START
estática - abuelo
estática - padres
estática - niño
ejemplo - abuelo
constructor - abuelo
instancia - padre
constructor - los padres
ejemplo - niño
constructor - niño
FIN

La respuesta obvia de esto es que los bloques de los padres ejecutan antes de sus hijos, pero eso podría ser sólo una coincidencia y no ayuda si dos las clases no están en la misma jerarquía.

EDIT:

que modifica el código ejemplo añadiendo esto a LoadTest.java:

class IAmAClassThatIsNeverUsed { 
    // Constructor 
    public IAmAClassThatIsNeverUsed() { 
     System.out.println("constructor - IAACTINU"); 
    } 

    // Instance init block 
    { 
     System.out.println("instance - IAACTINU"); 
    } 

    // Static init block 
    static { 
     System.out.println("static - IAACTINU"); 
    } 
} 

como lo implica el nombre de la clase, nunca hace referencia a la nueva clase en cualquier lugar. El nuevo programa produjo el mismo resultado que el anterior.

+1

ver allí (super concisa y clara): Un http://blog.sanaulla.info/2008/06/30/initialization-blocks-in-java/ – Benj

Respuesta

53

El inicializador estático de una clase se ejecuta cuando se accede por primera vez a la clase, ya sea para crear una instancia o para acceder a un método o campo estático.

Por lo tanto, para múltiples clases, esto depende totalmente del código que se ejecuta para hacer que esas clases se carguen.

+0

la clase puede cargarse durante el ciclo de resolución de un dependiente. Simplemente tener una declaración de una variable de una clase determinada requerirá la carga de esa clase. – alphazero

+0

Eso parece contrario a lo que dice la sección 12.4 (ver la excelente respuesta de Keith). –

+0

Estoy de acuerdo. La declaración de variable (creo) no lo hará, a menos que sea una variable estática con inicialización. –

84

Ver la sección 12.4 y 12.5 del JLS version 8, entran en detalles sangrientos sobre todo esto (12.4 para variables estáticas y 12.5 para variables de ejemplo).

Para inicialización estática (sección 12.4):

una clase o tipo de interfaz T se inicializará inmediatamente antes de la primera aparición de uno cualquiera de los siguientes:

  • T es una clase y una instancia de T es creado.
  • T es una clase y se invoca un método estático declarado por T.
  • Se asigna un campo estático declarado por T.
  • Se utiliza un campo estático declarado por T y el campo no es una variable constante (§4.12.4).
  • T es una clase de nivel superior (§7.6), y se ejecuta una declaración de afirmación (§14.10) léxicamente anidada dentro de T (§8.1.3).

(y varios palabra comadreja cláusulas)

+2

La mejor respuesta posible. ¡Gran trabajo! –

+0

Buena respuesta. Escaneé la página y contiene los fundamentos para el diseño orientado a objetos en lo que se refiere a Java. Por lo tanto, es una lectura obligada para cada desarrollador de Java. –

+0

Bueno. Directamente de los creadores –

29

respuestas de Keith y Chris son estupendos, sólo estoy añadiendo un poco más de detalle para mi pregunta específica.

Los bloques de ejecución estáticos se ejecutan en el orden en que se inicializan sus clases. Entonces, ¿qué orden es eso? Per JLS 12.4.1:

un tipo de clase o interfaz T se inicializará inmediatamente antes de la primera aparición de uno cualquiera de los siguientes:

  • T es una clase y una instancia de T se crea .
  • T es una clase y se invoca un método estático declarado por T.
  • Se asigna un campo estático declarado por T.
  • Se utiliza un campo estático declarado por T y el campo no es una variable constante (§4.12.4).
  • T es una clase de nivel superior, y se ejecuta una sentencia de afirmación (§14.10) anidada léxicamente dentro de T.

La invocación de ciertos métodos reflectantes en la clase Class y en el paquete java.lang.reflect también provoca la inicialización de la clase o la interfaz. Una clase o interfaz no se inicializará bajo ninguna otra circunstancia.

Para ilustrar, aquí hay un tutorial de lo que sucede en el ejemplo:

  1. Introduzca principal
  2. Imprimir "START"
  3. intento de crear la primera instancia del niño, lo que requiere la inicialización de Niño
  4. Intentar inicializar El niño provoca la inicialización del elemento primario
  5. intentar inicializar los padres provoca la inicialización de los abuelos
  6. Al comienzo de la inicialización de los abuelos, el bloque de inicialización estática de los abuelos se ejecuta
  7. Técnicamente, el objeto tiene la última palabra en la cadena de inicialización, en virtud de siendo el padre de los abuelos, pero no tiene nada que aportar
  8. Después de que termina el bloque de inicialización estático de Grandparent, el programa vuelve al bloque de inicialización estático de la matriz
  9. Después extremos del bloque de inicialización estática de los padres, el programa de verano al bloque de inicialización estática del niño
  10. En este punto, Niño es inicializado, por lo que su constructor puede proceder
  11. Desde IAmAClassThatIsNeverUsed nunca se hace referencia, nada de su código nunca se ejecuta, incluidos los tacos de inicializador estático
  12. El resto de este tutorial no se refiere a los inicializadores estáticos y se incluye únicamente para completar
  13. constructor del niño implicitl Y llama a super() (es decir, el constructor de Padres) constructor
  14. del padre llama implícitamente super() (es decir, el constructor de los abuelos) del constructor
  15. de los abuelos hace lo mismo, que no tiene ningún efecto (de nuevo, el objeto tiene nada que aportar)
  16. inmediatamente después de la llamada de constructor de los abuelos a super() viene una instancia del bloque de inicialización de los abuelos
  17. el resto de carreras del constructor del constructor de los abuelos y el constructor termina
  18. el programa vuelve a caer al constructor de Padres, inmediatamente después de su llamada a super() (es decir, Constructor de los abuelos) resuelve
  19. Como el anterior, inicializador ejemplo de los padres hace su cosa y su constructor termina hasta
  20. Del mismo modo, el programa vuelve a y completa el constructor del Niño
  21. En este punto, el objeto ha creado una instancia
  22. Imprimir "FIN"
  23. Terminar normalmente
+1

en 12.4.1 también encontramos: 'Antes de inicializar una clase, su superclase directa debe inicializarse, ... ' –

0

puede tener varias inicializadores estáticos y de instancia en la misma clase, por lo tanto,

  • inicializadores estáticos son llamados en el orden textual en que se declaran (de 12.4.2)
  • inicializadores de instancia son llamados en el orden textual en que se declaran (de 12.5)

Cada se ejecuta como si se era un solo bloque.

1

La inicialización de una clase consiste en ejecutar sus inicializadores estáticos y los inicializadores para campos estáticos (variables de clase) declarados en la clase.

La inicialización de una interfaz consiste en ejecutar los inicializadores para los campos (constantes) declarados en la interfaz.

Antes de inicializar una clase, su superclase directa debe inicializarse, pero las interfaces implementadas por la clase no se inicializan. De forma similar, las superinterfaces de una interfaz no se inicializan antes de que se inicialice la interfaz.

0

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

amablemente comprobar la documentación de Java.

continuación mencionado claramente no importa cómo pueden estática bloques están allí van a ser ejecutadas como un solo bloque en el orden en que aparecen

Así,

Mi entendimiento aquí es Java está buscando su código como

static{ 
i=1; 
i=2; 
} 

static int i;

es por eso que está recibiendo la salida 2

esperanza que esto sea útil

0

Hay un caso en el que no se recurra a un bloque estático.

class Super { 
    public static int i=10; 
} 
class Sub extends Super { 
    static { 
     system.out.println("Static block called"); 
    } 
} 
class Test { 
    public static void main (String [] args) { 
     system.out.println(Sub.i); 
    } 
} 

Las salidas de código anteriores 10

Cuestiones relacionadas