web-dev-qa-db-fra.com

Bloc statique dans Java non exécuté

class Test{
    public static void main(String arg[]){    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL);//SOP(9090);
        System.out.println(Mno.VAL+100);//SOP(9190);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}

Je sais qu'un bloc static exécuté lors du chargement de la classe. Mais dans ce cas, la variable d'instance à l'intérieur de la classe Mno est final, car le bloc static n'est pas en cours d'exécution.

Pourquoi est-ce si? Et si je supprimais le final, cela fonctionnerait-il bien?

Quelle mémoire sera allouée en premier, le static final variable ou le bloc static?

Si en raison du modificateur d'accès final la classe n'est pas chargée, alors comment la variable peut-elle obtenir de la mémoire?

86
Sthita
  1. UNE static final int champ est un constante de compilation et sa valeur est codée en dur dans la classe de destination sans référence à son origine;
  2. par conséquent, votre classe principale ne déclenche pas le chargement de la classe contenant le champ;
  3. par conséquent, l'initialiseur statique de cette classe n'est pas exécuté.

Plus précisément, le bytecode compilé correspond à ceci:

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

Dès que vous supprimez final, ce n'est plus une constante de compilation et le comportement spécial décrit ci-dessus ne s'applique pas. La classe Mno est chargée comme prévu et son initialiseur statique s'exécute.

132
Marko Topolnik

La raison pour laquelle la classe n'est pas chargée est que VAL est final [~ # ~] et [~ # ~] il est initialisé avec ne expression constante (9090). Si et seulement si ces deux conditions sont remplies, la constante est évaluée au moment de la compilation et "codée en dur" si nécessaire.

Pour empêcher l'expression d'être évaluée au moment de la compilation (et pour que la JVM charge votre classe), vous pouvez soit:

  • supprimez le mot clé final:

    static int VAL = 9090; //not a constant variable any more
    
  • ou changez l'expression de droite en quelque chose de non constant (même si la variable est toujours finale):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    
8
assylias

Si vous voyez le bytecode généré en utilisant javap -v Test.class, main () se présente comme:

public static void main(Java.lang.String[]) throws Java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method Java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method Java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method Java/io/PrintStream.println:(I)V
        26: return        

Vous pouvez clairement voir dans "11: sipush 9090 "cette valeur finale statique est directement utilisée, car Mno.VAL est une constante de temps de compilation. Par conséquent, il n'est pas nécessaire de charger la classe Mno. Par conséquent, le bloc statique de Mno n'est pas exécuté.

Vous pouvez exécuter le bloc statique en chargeant manuellement Mno comme ci-dessous:

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
5
Xolve

1) En fait, vous n'avez pas étendu cette classe Mno, donc au démarrage de la compilation, elle générera une constante de la variable VAL et lorsque l'exécution commencera lorsque cette variable sera nécessaire, sa charge sera de la mémoire.Il n'est donc pas nécessaire que votre référence de classe ne soit pas exécutée. .

2) si une classe A étend cette classe Mno à ce moment-là, ce bloc statique est inclus dans la classe A si vous faites cela, alors ce bloc statique est exécuté. par exemple .. la classe publique A étend Mno {

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(Mno.VAL);//SOP(9090);
    System.out.println(Mno.VAL+100);//SOP(9190);
}

}

class Mno{
      final static int VAL=9090;
    static`{`
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
1
Ketan_Patel

Pour autant que je sache, il sera exécuté par ordre d'apparition. Par exemple :

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

imprimera

  trace init1
  trace middle
  trace init2

Je viens de le tester et la statique est initialisée (=> print) lorsque la classe "Statique" est effectivement utilisée et "exécutée" dans un autre morceau de code (mon cas j'ai fait "new Statique ()".

0
Fabyen