Blok statyczny w Javie nie jest wykonywany

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 jest po załadowaniu klasy. Ale w tym przypadku zmienną instancji wewnątrz klasy Mno jest final, z tego powodu blok static nie jest wykonywany.

Dlaczego tak jest? A jeśli usunę final, to będzie dobrze?

Która pamięć zostanie przydzielona jako pierwsza, zmienna static final czy blok static?

Jeśli z powodu modyfikatora dostępu final klasa nie zostanie załadowana, to w jaki sposób zmienna może uzyskać pamięć?

Author: A.H., 2013-05-31

5 answers

  1. A static final int pole jest stałą czasową kompilacji , a jego wartość jest zakodowana na twardo do klasy docelowej bez odniesienia do jej pochodzenia;
  2. dlatego Twoja główna klasa nie uruchamia ładowania klasy zawierającej pole;
  3. dlatego statyczny inicjalizator w tej klasie nie jest wykonywany.

W szczegółach, skompilowany kod bajtowy odpowiada temu:

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

Jak tylko usuniesz final, nie jest to już czas kompilacji stałe i specjalne zachowanie opisane powyżej nie ma zastosowania. Klasa Mno jest ładowana zgodnie z oczekiwaniami, a jej inicjalizacja statyczna jest wykonywana.

 130
Author: Marko Topolnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-31 11:49:49

Powodem, dla którego klasa nie jest wczytywana jest to, że VAL jest final i jest inicjalizowana 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 w razie potrzeby "zakodowana na twardo".

Aby zapobiec ocenie wyrażenia podczas kompilacji (i aby JVM załadował Twoją klasę), możesz:

  • Usuń ostatnie słowo kluczowe:

    static int VAL = 9090; //not a constant variable any more
    
  • Lub zmienić prawo wyrażenie strony do czegoś nie stałego (nawet jeśli zmienna jest jeszcze ostateczna):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    
 8
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-05 03:23:41

Jeśli widzisz wygenerowany bajt za pomocą javap -v Test.class, main() wyświetla się w następujący sposób:

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        

Widać wyraźnie w "11: sipush 9090", że statyczna wartość końcowa jest bezpośrednio używana, 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);
    }
}
 5
Author: Xolve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-05 19:05:25

1)W zasadzie nie masz rozszerzeń tej klasy Mno więc przy starcie kompilacji wygeneruje ona stałą zmiennej VAL a przy starcie wykonania gdy ta zmienna jest potrzebna jej obciążenie z memory.so its nie wymaga referencji klasy, aby statyczny bock nie został wykonany.

2)jeśli Klasa rozszerza klasę Mno w tym czasie, że statyczny blok jest zawarty w klasie jeśli to zrobisz, to ten statyczny blok jest wykonywany. 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);
    }
}
 1
Author: Ketan_Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 05:30:25

Z tego, co wiem, zostanie wykonana w kolejności pojawienia 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

  trace init1
  trace middle
  trace init2

Właśnie go przetestowałem i statyki są inicjalizowane (=>print), gdy Klasa "Statique" jest rzeczywiście używana i "wykonywana" w innym fragmencie kodu (w moim przypadku zrobiłem "new Statique ()".

 0
Author: Fabyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-31 09:23:47