Quand l'initialisation de classe statique se produit-elle?

110

Quand les champs statiques sont-ils initialisés? Si je n'instancie jamais une classe, mais que j'accède à un champ statique, TOUS les blocs statiques et les méthodes statiques privées utilisés pour instancier les champs statiques privés sont-ils appelés (dans l'ordre) à cet instant?

Et si j'appelle une méthode statique? Exécute-t-il également tous les blocs statiques? Avant la méthode?

Tony R
la source
Similaire pour les blocs d'initialisation statiques: stackoverflow.com/questions/2007666/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

156

L'initialisation statique d'une classe se produit normalement juste avant la première fois que l'un des événements suivants se produit:

  • une instance de la classe est créée,
  • une méthode statique de la classe est invoquée,
  • un champ statique de la classe est attribué,
  • un champ statique non constant est utilisé, ou
  • pour une classe de niveau supérieur, une instruction assert imbriquée lexicalement dans la classe est exécutée 1 .

Voir JLS 12.4.1 .

Il est également possible de forcer une classe à s'initialiser (si elle ne l'a pas déjà été) en utilisant Class.forName(fqn, true, classLoader)ou la forme courteClass.forName(fqn)


1 - La dernière puce était présente dans le JLS pour Java 6 à Java 8, mais c'était apparemment une erreur dans la spécification. Il a finalement été corrigé dans le JLS Java 9: ​​voir source .

Stephen C
la source
9
Il y a cependant un piège commun. Les primitives et les Strings sont substitués et non référencés. Si vous référencez a class Other { public static final int VAL = 10; }d'une classe MyClass { private int = Other.VAL; }, la classe Otherne sera pas chargée. Au lieu de cela, le compilateur remplacera simplement le champ final au moment de la compilation.
Rafael Winterhalter
6
@RafaelWinterhalter - oui ... c'est le cas du champ statique constant .
Stephen C
2
@RafaelWinterhalter, ce n'est pas vrai pour toutes les primitives ou Stringvariables «finales statiques» , seulement celles initialisées par une expression constante.
Lew Bloch
1
Oui, et le champ n'a même pas besoin d'être staticalors que c'est un cas courant.
Rafael Winterhalter
1
C'est le même langage de programmation. Oui.
Stephen C le
14

Les champs statiques sont initialisés lors de la "phase" d' initialisation du chargement de la classe (chargement, liaison et initialisation) qui comprend des initialiseurs statiques et des initialisations de ses champs statiques. Les initialiseurs statiques sont exécutés dans un ordre textuel tel que défini dans la classe.

Prenons l'exemple:

public class Test {

   static String sayHello()  {
      return a;
   }

   static String b = sayHello(); // a static method is called to assign value to b.
                                 // but its a has not been initialized yet.

   static String a = "hello";

   static String c = sayHello(); // assignes "hello" to variable c

    public static void main(String[] arg) throws Throwable {
         System.out.println(Test.b); // prints null
         System.out.println(Test.sayHello()); // prints "hello"
    }
}

Le Test.b s'imprime nullcar lorsque le a sayHelloété appelé dans la portée statique, la variable statique an'a pas été initialisée.

Naikus
la source
6
À proprement parler, l'initialisation n'est pas une "phase" de chargement de classe. En effet, certaines classes peuvent être chargées mais jamais initialisées si l'application ne les utilise pas réellement.
Stephen C
@Stephen C Vous avez raison, je l'ai utilisé par manque de meilleur terme, je vais peut-être le citer.
naikus
@StephenC cela signifie-t-il que pendant le chargement de la classe, il affecte de la mémoire aux variables statiques (& méthodes) mais que ces variables statiques ne sont pas initialisées avec les valeurs fournies dans le code? car ici, il semble que lorsque b-> sayHello () -> a, 'a' est en mémoire mais la valeur ne lui est pas encore attribuée.
Shabbir Essaji
Fondamentalement, oui.
Stephen C
1

Oui, tous les initialiseurs statiques sont exécutés avant que vous n'accédiez à la classe pour la première fois. S'il en était autrement, j'appellerais cela un bug.

Nikita Rybak
la source
Il existe des moyens de faire référence à une classe sans l'initialiser.
Lew Bloch