Dans quel ordre les blocs d’initialisation d’instance / statique sont-ils exécutés en Java?

Disons qu’un projet contient plusieurs classes, chacune ayant un bloc d’initialisation statique. Dans quel ordre ces blocs fonctionnent-ils? Je sais que dans une classe, ces blocs sont exécutés dans l’ordre dans lequel ils apparaissent dans le code. J’ai lu que c’est la même chose dans toutes les classes, mais un exemple de code que j’ai écrit est en désaccord avec cela. J’ai utilisé ce code:

package pkg; public class LoadTest { public static void main(Ssortingng[] 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"); } } 

et a obtenu cette sortie:

DÉBUT
statique – grand-parent
statique – parent
statique – enfant
exemple – grand-parent
constructeur – grand-père
instance – parent
constructeur – parent
instance – enfant
constructeur – enfant
FIN

La réponse évidente à cette question est que les blocs des parents s’exécutent avant leurs enfants, mais cela pourrait être une simple coïncidence et cela n’aide pas si deux classes ne sont pas dans la même hiérarchie.

MODIFIER:

J’ai modifié mon code exemple en ajoutant ceci à 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"); } } 

Comme l’indique le nom de la classe, je n’ai jamais référencé la nouvelle classe. Le nouveau programme a produit le même résultat que l’ancien.

L’initialiseur statique d’une classe est exécuté lors du premier access à la classe, soit pour créer une instance, soit pour accéder à une méthode ou un champ statique.

Donc, pour plusieurs classes, cela dépend totalement du code exécuté pour que ces classes soient chargées.

Reportez-vous aux sections 12.4 et 12.5 de la version 8 de JLS , qui détaillent tout cela (12.4 pour les variables static et 12.5 pour les variables d’instance).

Pour l’initialisation statique (section 12.4):

Une classe ou un type d’interface T sera initialisé immédiatement avant la première occurrence de l’un des éléments suivants:

  • T est une classe et une instance de T est créée.
  • T est une classe et une méthode statique déclarée par T est invoquée.
  • Un champ statique déclaré par T est affecté.
  • Un champ statique déclaré par T est utilisé et le champ n’est pas une variable constante (§4.12.4).
  • T est une classe de premier niveau (§7.6), et une instruction assert (§14.10) nestede lexicalement dans T (§8.1.3) est exécutée.

(et plusieurs clauses de Weasel-Word)

Les réponses de Keith et de Chris sont toutes deux excellentes, j’ajoute juste un peu plus de détails pour ma question spécifique.

Les blocs d’initialisation statiques s’exécutent dans l’ordre d’initialisation de leurs classes. Alors, quel est cet ordre? Par JLS 12.4.1:

Une classe ou un type d’interface T sera initialisé immédiatement avant la première occurrence de l’un des éléments suivants:

  • T est une classe et une instance de T est créée.
  • T est une classe et une méthode statique déclarée par T est invoquée.
  • Un champ statique déclaré par T est affecté.
  • Un champ statique déclaré par T est utilisé et le champ n’est pas une variable constante (§4.12.4).
  • T est une classe de premier niveau et une instruction assert (§14.10) nestede lexicalement dans T est exécutée.

L’invocation de certaines méthodes de reflection dans la classe Class et dans le package java.lang.reflect provoque également l’initialisation de la classe ou de l’interface. Une classe ou une interface ne sera pas initialisée sous aucune autre circonstance.

Pour illustrer cela, voici un aperçu de ce qui se passe dans l’exemple:

  1. Entrer principal
  2. Imprimer “START”
  3. Tentative de création de la première instance de Child, ce qui nécessite une initialisation de Child
  4. La tentative d’initialisation de Child provoque l’initialisation de Parent
  5. La tentative d’initialisation du parent entraîne l’initialisation de grand-parent
  6. Au début de l’initialisation de Grandparent, le bloc d’initialisation statique de Grandparent est exécuté
  7. Techniquement, Object obtient le dernier mot dans la chaîne d’initialisation en tant que parent de grand-parent, mais il n’a rien à apporter
  8. Lorsque le bloc d’initialisation statique de Grandparent se termine, le programme revient au bloc d’initialisation statique de Parent
  9. Après la fin du bloc d’initialisation statique de Parent, le programme revient au bloc d’initialisation statique de l’enfant
  10. À ce stade, Child est initialisé, son constructeur peut donc continuer
  11. Puisque IAmAClassThatIsNeverUsed n’est jamais référencé, aucun de ses codes ne s’exécute, y compris les blocs d’initialisation statiques
  12. Le rest de cette procédure ne concerne pas les initialiseurs statiques et n’est inclus que pour être complet
  13. Le constructeur de l’enfant appelle implicitement super () (c’est-à-dire le constructeur de Parent)
  14. Le constructeur du parent appelle implicitement super () (c’est-à-dire le constructeur de grand-parent)
  15. Le constructeur de grand-père fait la même chose, ce qui n’a aucun effet (encore une fois, Object n’a rien à apporter)
  16. Immédiatement après l’appel du constructeur de grand-parent à super () vient le bloc d’initialisation d’instance de Grandparent
  17. Le rest du constructeur du constructeur de Grandparent s’exécute et le constructeur termine
  18. Le programme revient au constructeur de Parent, immédiatement après son appel à super () (c’est-à-dire le constructeur de grand-parent)
  19. Comme ci-dessus, l’initialiseur d’instance de Parent fait son travail et son constructeur termine
  20. De même, le programme retourne et termine le constructeur de Child
  21. À ce stade, l’object a été instancié
  22. Imprimer “FIN”
  23. Termine normalement

L’initialisation d’une classe consiste à exécuter ses initialiseurs statiques et les initialiseurs pour les champs statiques (variables de classe) déclarés dans la classe.

L’initialisation d’une interface consiste à exécuter les initialiseurs pour les champs (constantes) déclarés dans l’interface.

Avant qu’une classe soit initialisée, sa super-classe directe doit être initialisée, mais les interfaces implémentées par la classe ne sont pas initialisées. De même, les super-interfaces d’une interface ne sont pas initialisées avant que l’interface ne soit initialisée.

Vous pouvez avoir plusieurs initialiseurs statiques et d’instance dans la même classe, donc

  • Les initialiseurs statiques sont appelés dans l’ordre textuel où ils sont déclarés (à partir de 12.4.2 )
  • Les initialiseurs d’instance sont appelés dans l’ordre textuel où ils sont déclarés (à partir de 12.5 )

Chacun est exécuté comme s’il s’agissait d’un bloc unique.

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

veuillez vérifier la documentation de Java.

alors clairement mentionné, peu importe la façon dont les blocs statiques sont là, ils seront exécutés dans un seul bloc dans l’ordre où ils apparaissent

Alors,

Ma compréhension ici est que java regarde votre code comme

 static{ i=1; i=2; } 

static int i;

c’est pourquoi vous obtenez la sortie 2

j’espère que c’est utile

Il y a un cas dans lequel un bloc statique ne sera pas appelé.

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

Les sorties de code ci-dessus 10