54 votes

Pourquoi les champs statiques ne sont pas initialisés à temps?

Quelqu'un m'a dit:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

Je me demande, n'est-ce pas un bug? Pourquoi les objets statiques ne sont pas initialisées avant l'exécution du constructeur?

--mise à jour

J'avais juste copié ce programme d'exemple et sans attention, je pensais que nous parlions de 2 champs d'Objet, maintenant que j'ai vu que le premier est un MyClass champ.. :/

Acceptée-réponse marque va à Pyrolistical par le dévouement à expliquer.

Aussi, merci Kevin Brock.

Je remercie tous ceux qui ont soutenu, je remercie l'académie, les amis,.. XD

46voto

Pyrolistical Points 12457

À cause de la statique sont initialisés dans l'ordre où ils sont donnés dans le code source.

Check this out:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static MyClass myClass2 = new MyClass();
  public MyClass() {
    System.out.println(myClass);
    System.out.println(myClass2);
  }
}

À imprimer:

null
null
myClassObject
null

MODIFIER

Ok, nous allons dessiner à être un peu plus clair.

Initialiser des variables statiques, un par un dans l'ordre tel que déclaré dans le code source.

Depuis la première statique est initialisé avant le repos, lors de l'initialisation de la première statique le reste sont nuls ou les valeurs par défaut.

Lors de l'initiation de la deuxième statique de la première statique est correct mais le reste est toujours la valeur null ou par défaut.

Est-ce clair?

EDIT 2

Comme Varman a souligné la référence à elle-même sera nulle alors qu'elle est en cours d'initialisation. Qui a de sens que si vous pensez à ce sujet.

28voto

Kevin Brock Points 4695

Essayons une autre façon d'expliquer cela...

C'est la séquence de la JVM va de travers lors de la première référence de la classe MyClass.

  1. Charger le byte-code dans la mémoire.
  2. Mémoire pour le stockage statique est désactivée (zéro binaire).
  3. Initialiser la classe:
    1. L'exécution de chacune d'initialiseur statique dans l'ordre dans lequel il apparaît, ce qui inclut les variables statiques et static { ... } blocs.
    2. JVM initialise ensuite votre myClass variable statique à une nouvelle instance de l' MyClass.
    3. Lorsque cela se produit, la JVM avis qu' MyClass est déjà chargé (byte-code) et dans le processus en cours d'initialisation, de sorte qu'il ignore l'initialisation.
    4. Allouer de la mémoire sur le tas pour l'objet.
    5. Exécuter constructeur.
    6. Imprimer la valeur de obj qui est encore en null (car il ne fait pas partie de la tas et de constructeur initialisé les variables).
    7. Lorsque constructeur finitions, exécuter ensuite initialiseur statique qui définit obj d'une nouvelle instance de l' Object.
  4. Initialisation de classe fait. À partir de ce point, tous les constructeur appelle va se comporter comme vous prétendez/attendre - c'est - obj ne serait pas null , mais une référence à un Object de l'instance.

Rappelez-vous que Java spécifie qu'un final variable est attribuée une valeur une fois. Il n'est pas qu'il est garanti pour être affecté d'une valeur lorsque les références de code, à moins que vous vous assurez que les références de code après il est affecté.

Ce n'est pas un bug. C'est la manière définie pour gérer l'utilisation de la classe au cours de sa propre initialisation. Si ce n'était pas le cas, la JVM irait dans une boucle infinie. Voir l'étape n ° 3.3 (si la JVM ne sautez pas de l'initialisation pour une classe qui est dans le processus de l'initialisation, il suffit de garder initialisation - boucle infinie).

Note que bien, tout cela se fait sur le même thread qui fait référence à la classe. Deuxièmement, la JVM garantit que l'initialisation complète avant toute autre thread n'est autorisé à utiliser cette classe.

19voto

Slava Imeshev Points 482

C'est parce que Java exécute la statique de la section afin qu'il ne soit déclaré. Dans votre cas, la séquence est

  1. new MyClass
  2. nouvel Objet

Quand #1 est exécutée, obj n'est pas encore initialisé, de sorte qu'il imprime la valeur null. Essayez ce qui suit et vous verrez la différence:

class MyClass {
  private static final Object obj = new Object();
  private static MyClass myClass = new MyClass();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

De manière générale, il est préférable d'éviter une telle construire tous ensemble. Si vous essayez de créer un singleton, c'est comment ce fragment de code devrait ressembler à ça:

class MyClass {

  private static final MyClass myClass = new MyClass();

  private Object obj = new Object();

  private MyClass() {
    System.out.println(obj); // will print null once
  }
}

2voto

JonH Points 20454

0voto

antony Points 104

c'est parce que les champs statiques sont initialisés dans le même ordre qu'ils ont défini.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X