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?
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;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.
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; }
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);
}
}
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);
}
}
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 ()".