web-dev-qa-db-fra.com

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

Supposons qu'un projet contient plusieurs classes, chacune d'entre elles ayant un bloc d'initialisation statique. Dans quel ordre ces blocs fonctionnent-ils? Je sais qu'au sein d'une classe, de tels blocs sont exécutés dans l'ordre dans lequel ils apparaissent dans le code. J'ai lu que c'était la même chose d'une classe à l'autre, mais un exemple de code que j'ai écrit n'est pas d'accord avec cela. J'ai utilisé ce code:

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");
    }
}

et obtenu cette sortie:

DÉBUT
statique - grand-parent
statique - parent
statique - enfant
exemple - grand-parent
constructeur - grand-parent
instance - parent
constructeur - parent
instance - enfant
constructeur - enfant
FIN

La réponse évidente à cela est que les blocs des parents fonctionnent avant ceux de leurs enfants, mais cela pourrait simplement être une coïncidence et n'aiderait pas si deux classes n'étaient pas dans la même hiérarchie.

MODIFIER:

J'ai modifié mon exemple de code en l'ajoutant à 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 nulle part. Le nouveau programme a produit le même résultat que l'ancien.

87
Pops

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

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

59
Chris Jester-Young

Reportez-vous aux sections 12.4 et 12.5 du JLS version 8 , pour en savoir plus sur tout cela (12.4 pour les variables statiques et 12.5 pour les variables d'instance).

Pour l’initialisation statique (section 12.4):

Une classe ou une interface de type T sera initialisée immédiatement avant la première occurrence de l’un des opérations suivantes:

  • 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 appelé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 niveau supérieur (§7.6) et une instruction d'assertion (§14.10) imbriquée lexicalement dans T (§8.1.3) est exécutée.

(et plusieurs clauses Weasel-Word)

89
Keith Randall

Les réponses de Keith et de Chris sont excellentes. J'ajoute juste quelques détails supplémentaires pour ma question spécifique.

Les blocs d'initialisation statiques s'exécutent dans l'ordre d'initialisation de leurs classes. Alors, quel ordre est-ce? Selon JLS 12.4.1:

Une classe ou une interface de type T sera initialisée immédiatement avant la première occurrence de l’un des opérations suivantes:

  • 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 appelé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 niveau supérieur et une instruction assert (§14.10) imbriquée lexicalement dans T est exécutée. 

L'invocation de certaines méthodes de réflexion dans la classe Class et dans le package Java.lang.reflect entraîne également l'initialisation de la classe ou de l'interface. Une classe ou une interface ne sera initialisée dans aucune autre circonstance.

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

  1. Entrez main
  2. Imprimer "START"
  3. Tentative de création d'une première instance de Child, nécessitant l'initialisation de Child
  4. Toute tentative d'initialisation de Child provoque l'initialisation de Parent
  5. Toute tentative d'initialisation du parent provoque l'initialisation de grand-parent
  6. Au début de l'initialisation de Grand-parent, le bloc d'initialisation statique de ce dernier est exécuté
  7. Techniquement, Object a le dernier mot dans la chaîne d'initialisation en tant que parent du grand-parent, mais il n'a rien à contribuer
  8. Une fois le bloc d'initialisation statique de grand-parent terminé, le programme revient au bloc d'initialisation statique de Parent
  9. Après la fin du bloc d'initialisation statique du parent, le programme revient au bloc d'initialisation statique de Child
  10. À ce stade, l'enfant est initialisé afin que son constructeur puisse continuer
  11. IAmAClassThatIsNeverUsed n'étant jamais référencé, aucun de ses codes ne s'exécute, y compris les blocs d'initialisation statiques
  12. Le reste de cette procédure ne concerne pas les initialiseurs statiques et n'est inclus que par souci d'exhaustivité.
  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-parent fait la même chose, ce qui n'a aucun effet (encore une fois, Object n'a rien à contribuer)
  16. Immédiatement après l'appel du constructeur de grand-parent à super (), le bloc d'initialisation d'instance de grand-parent
  17. Le reste du constructeur du constructeur de Grandparent s'exécute et le constructeur se 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 se termine
  20. De même, le programme retourne au constructeur de Child et le complète.
  21. A ce stade, l'objet a été instancié
  22. Imprimer "FIN"
  23. Terminer normalement
31
Pops

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

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

Avant qu'une classe ne 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 l'initialisation de l'interface.

1
Bala

http://docs.Oracle.com/javase/tutorial/Java/javaOO/initial.html

veuillez vérifier la documentation Java.

puis clairement mentionné, peu importe la façon dont les blocs statiques sont présents, ils seront exécutés comme un seul bloc dans l'ordre dans lequel ils apparaissent

Alors,

Si je comprends bien, Java cherche votre code comme

static{
i=1;
i=2;
}

statique int i;

c'est pourquoi vous obtenez la sortie 2

espérons que cela vous sera utile

0
Avinash Perla

Il existe 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 (String [] args) {
        system.out.println(Sub.i);
    } 
}

Le code ci-dessus renvoie 10

0
Java Main
class A {
  public A() { 
    // 2
  }
}

class B extends A{
  static char x = 'x'; // 0
  char y = 'y'; // 3
  public B() { 
    // 4
  }

  public static void main(String[] args) {
    new B(); // 1
  }
}

Les chiffres dans le commentaire indiquent l'ordre d'évaluation, le plus petit, le plus tôt.

Comme le montre l'exemple,

  1. variable statique
  2. principale
  3. constructeur de superclasse
  4. variable d'instance
  5. constructeur
0
GraceMeng

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 seul bloc.

0
Martin Tapp