Bloc statique en Java non exécuté

class Test{ public static void main(Ssortingng 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 dans la classe Mno est final , car le bloc static n’est pas en cours d’exécution.

Pourquoi est-ce si? Et si je retirais la final , cela fonctionnerait-il bien?

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

Si, en raison du modificateur d’access final la classe n’est pas chargée, comment la variable peut-elle obtenir de la mémoire?

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

En détail, le bytecode compilé correspond à ceci:

 public static void main(Ssortingng 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.

La raison pour laquelle la classe n’est pas chargée est que VAL est final ET qu’il est initialisé avec une 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 éviter que l’expression ne soit évaluée au moment de la compilation (et pour que la JVM charge votre classe), vous pouvez soit:

  • supprimer 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 définitive):

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

Si vous voyez un bytecode généré à l’aide de javap -v Test.class , main () sort comme:

 public static void main(java.lang.Ssortingng[]) 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 // Ssortingng **MAIN METHOD 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/Ssortingng;)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(Ssortingng 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); } } 

1) En fait, vous n’aurez pas étendu cette classe Mno quand la compilation démarrera, elle générera une constante de la variable VAL et quand l’exécution démarrera quand cette variable sera nécessaire, son chargement revient à memory.so ne sera pas requirejs votre référence de classe .

2) si une classe é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(Ssortingng 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); } } 

Pour autant que je sache, il sera exécuté dans l’ordre d’apparition. Par exemple :

  public class Statique { public static final Ssortingng value1 = init1(); static { System.out.println("trace middle"); } public static final Ssortingng value2 = init2(); public static Ssortingng init1() { System.out.println("trace init1"); return "1"; } public static Ssortingng init2() { System.out.println("trace init2"); return "2"; } } 

imprimera

  trace init1 trace middle trace init2 

Je viens de le tester et les statiques sont initialisées (=> 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 ()”).