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);
}
}
Wiem, że static
blok wykonywany po załadowaniu klasy. Ale w tym przypadku zmienną instancji wewnątrz klasy Mno
jest final
, ponieważ static
blok nie jest wykonywany.
Dlaczego to jest takie? A gdybym usunął final
, czy to zadziała?
Która pamięć zostanie przydzielona jako pierwsza, static final
zmienna czy static
blok?
Jeśli z powodu final
modyfikatora dostępu klasa nie jest ładowana, to w jaki sposób zmienna może uzyskać pamięć?
java
static
access-modifiers
Sthita
źródło
źródło
Odpowiedzi:
static final int
Pole jest stałą czasu kompilacji , a jego wartość jest sztywno do klasy przeznaczenia bez odniesienia do jego pochodzenia;W szczególności, skompilowany kod bajtowy odpowiada temu:
public static void main(String arg[]){ System.out.println("**MAIN METHOD"); System.out.println(9090) System.out.println(9190) }
Zaraz po usunięciu
final
nie jest to już stała czasu kompilacji, a specjalne zachowanie opisane powyżej nie ma zastosowania.Mno
Klasa jest ładowana zgodnie z oczekiwaniami i jego statyczna initializer wykonany.źródło
Powodem, dla którego klasa nie jest załadowany jest to, że
VAL
jestfinal
i to jest inicjowany z wyrażeniem stałym (9090). Jeśli i tylko wtedy, gdy te dwa warunki są spełnione, stała jest oceniana w czasie kompilacji i „zakodowana” w razie potrzeby.Aby zapobiec ocenie wyrażenia w czasie kompilacji (i zmusić maszynę JVM do załadowania Twojej klasy), możesz:
usuń ostatnie słowo kluczowe:
static int VAL = 9090; //not a constant variable any more
lub zmień wyrażenie po prawej stronie na coś niestałego (nawet jeśli zmienna jest nadal ostateczna):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
źródło
Jeśli zobaczysz wygenerowany kod bajtowy za pomocą
javap -v Test.class
, main () wygląda tak: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
W "
11: sipush 9090
" można wyraźnie zobaczyć, że statyczna wartość końcowa jest używana bezpośrednio, ponieważ Mno.VAL jest stałą czasową kompilacji. Dlatego nie jest wymagane ładowanie klasy Mno. Stąd statyczny blok Mno nie jest wykonywany.Możesz wykonać blok statyczny, ręcznie ładując Mno, jak poniżej:
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); } }
źródło
Właściwie nie rozszerzyłeś tej klasy Mno, więc po uruchomieniu kompilacji wygeneruje stałą o zmiennej VAL, a gdy rozpocznie się wykonywanie, gdy ta zmienna jest potrzebna, jej obciążenie pochodzi z pamięci. Nie jest więc wymagane, aby odwołanie do klasy nie było wykonywane.
jeśli klasa
A
rozszerza klasęMno
, blok statyczny jest zawarty w klasie,A
jeśli to zrobisz, wykonywany jest ten blok statyczny. Na przykład..public class A extends 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); } }
źródło
O ile wiem, zostanie to wykonane w kolejności pojawiania się. Na przykład :
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"; } }
wydrukuje
Właśnie to przetestowałem i statyka jest inicjalizowana (=> print), gdy klasa "Statique" jest faktycznie używana i "wykonywana" w innym fragmencie kodu (w moim przypadku zrobiłem "new Statique ()".
źródło
Statique
klasę wykonującnew Statique()
. W zadanym pytaniuMno
klasa w ogóle nie jest załadowana.