2012-11-25 4 views
7

Possible en double:
Java static class initialization
in what order are static blocks and static variables in a class executed?ordre d'initialisation variable statique, Java

Quand je lance ce code, la réponse est 1, je pensais que ce serait 2. Que est l'ordre d'initialisation et la valeur de k dans chaque étape?

public class Test { 

static {k = 2;} 
static int k = 1; 

public static void main(String[] args) { 
    System.out.println(k); 
} 
} 

Édition 1: Comme une suite à "k est définie à la valeur par défaut" alors pourquoi ce code suivant ne compile pas? Theres une erreur "Impossible de référencer un champ avant qu'il ne soit défini".

public class Test { 

static {System.out.println(k);} 
static int k=1; 

public static void main(String[] args) { 
    System.out.println(k); 
} 
} 

Edit 2: Pour une Unknow me^raison, il fonctionne quand au lieu de "k" son "Test.k".

Merci pour toutes les réponses. ceci sera suffisant: D

+1

D'abord, la valeur par défaut sera attribuée à k, puis, à partir du haut, le code statique sera exécuté et 2 seront attribués, puis 1 sera attribué. Ensuite, la fonction principale est appelée et imprimée k. 'static int k = 1' est effectivement' static int k; 'declaration, alors' static {k = 1; } ' – nhahtdh

+0

@KennyTM Oui, si j'avais couru le chemin comme dans ce post Vous collez, je saurais ce qui se passe. – Hoto

+0

@nhahtdh Une valeur par défaut sera-t-elle attribuée à k? Alors, pourquoi ce code n'a pas comiple: public class Test { \t \t statique {System.out.println (k); k = 2;} \t int k statique; \t \t public static void main (String [] args) { \t \t System.out.println (k); \t} } – Hoto

Répondre

7

Ils sont exécutés dans l'ordre dans lequel vous les écrivez. Si le code est:

public class Test { 

    static int k = 1; 
    static {k = 2;} 

    public static void main(String[] args) { 
     System.out.println(k); 
    } 

} 

alors la sortie devient 2.

L'ordre d'initialisation est la suivante: ..the class variable initializers and static initializers of the class..., in textual order, as though they were a single block.

Et les valeurs (pour votre code) sont: k = 0 (par défaut), alors il est réglé sur 2, il est remis à 1.

Vous pouvez vérifier qu'il est effectivement réglé sur 2 en exécutant le code suivant:

private static class Test { 

    static { 
     System.out.println(Test.k); 
     k = 2; 
     System.out.println(Test.k); 
     } 
    static int k = 1; 

    public static void main(String[] args) { 
     System.out.println(k); 
    } 
} 
+0

Ce n'est pas ce que je voulais dire dans ma question. Je voulais l'ordre d'initialisation et les valeurs de k dans chaque étape. – Hoto

+0

Ok, j'ai ajouté une explication plus détaillée. – tibtof

+0

Ouais ... mais maintenant il y a un peu de chaos dans votre réponse xD – Hoto

3

Réponse courte

Lorsque l'initialisation de la classe commence, k aura une valeur initiale de 0.

Le bloc statique (puisqu'elle précède l'attribution dans la déclaration) est ensuite exécutée, et k sera affecté 2.

Ensuite, l'initialiseur dans la déclaration est exécuté et k est affecté 1.

longue explication

Utilisons this example, puisque votre exemple est un peu simple:

class TestInitOrder { 
    static { 
    System.out.println(TestInitOrder.stat1); 
    System.out.println(TestInitOrder.stat2); 
    System.out.println(TestInitOrder.str); 
    System.out.println(TestInitOrder.str2); 

    str = "something"; 

    System.out.println(TestInitOrder.str); 
    System.out.println(TestInitOrder.str2); 
    System.out.println(TestInitOrder.lazy); 
    System.out.println(TestInitOrder.second); 
    } 

    private static final int stat1 = 10; 
    static final String str2 = "sdfff"; 
    static String str = "crap"; 
    private static int stat2 = 19; 
    static final Second second = new Second(); 
    static final int lazy; 

    static { 
    lazy = 20; 
    } 

    static { 
    System.out.println(TestInitOrder.str2); 
    System.out.println(TestInitOrder.stat2); 
    System.out.println(TestInitOrder.str); 
    System.out.println(TestInitOrder.lazy); 
    System.out.println(TestInitOrder.second); 
    } 

    public static void main(String args[]) { 
    } 

} 

class Second { 
    public Second() { 
    System.out.println(TestInitOrder.second); 
    } 
} 

Selon Java Language Specification, de section 4.12.5:

Chaque variable dans un programme doit avoir une valeur avant que sa valeur soit utilisée:

  • Chaque variable de classe, variable d'instance, ou d'un composant de tableau est initialisé avec une valeur par défaut lors de sa création

(Les lignes suivantes de la spécification spécifier la valeur par défaut pour tous les types, essentiellement une certaine forme de 0, comme 0, 0.0d, null, false, etc.)

Alors avant de la classe est initialisé (en raison de l'un des these reasons), les variables tiendra une valeur initiale.

Selon le detailed initialization procedure (seules les étapes intéressantes sont cités ici, et moi qui souligne):

6. [...] Ensuite, initialiser les final variables de classe et champs d'interfaces dont les valeurs sont à la compilationexpressions constantes (§8.3.2.1, §9.3.1, §13.4.9, §15.28).

[...]

9. Ensuite, exécutez l'une des initialiseurs variables de classe et initialiseurs statiques de la classe, ou les initialiseurs sur le terrain de l'interface, dans l'ordre textuel, comme si elles étaient un seul bloc .

Penchons-nous à l'étape 6, avec les 4 final variables de classe: stat1, str2, second, lazy.

Depuis 10 est l'expression constante, et ainsi est "sdfff", et en raison de l'ordre d'exécution, il est impossible de observer la valeur initiale pour str2 et stat1. Pour faire une observation, le plus tôt possible est à l'étape 9.

Le cas de second montre que lorsque le membre de droite n'est pas une expression de constante de compilation, sa valeur initiale est visible.

Le cas de lazy est différent, car l'affectation est faite en bloc statique, et se produit donc à l'étape 9 - il est donc possible d'observer sa valeur initiale. (Eh bien, le compilateur vérifie soigneusement que lazy est affecté exactement une fois).


Après l'initialisation de variables de classe finale avec une expression constante de temps de compilation vient l'exécution des blocs statiques et le reste des initializers.

Comme vous pouvez le voir dans l'exemple, les blocs statiques et l'initialisation se produit selon l'ordre textuel - démontré avec l'utilisation de str variable - il est d'abord imprimé comme null, puis something, puis crap.

+0

@EJP: Notez que 2 conditions 1) ** final ** variables de classe et 2) initializer est une constante de compilation qui est faite dans étape 6. Pas de contradiction ici. Vous pouvez même consulter le programme sur ideone. – nhahtdh

Questions connexes