Статический блок в Java не выполнен

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); } } 

Я знаю, что static блок выполняется при загрузке classа. Но в этом случае переменная экземпляра внутри classа Mno является final , из-за чего static блок не выполняется.

Почему это так? И если я удалю final , будет ли он работать нормально?

Какая память будет выделена первой, static final переменная или static блок?

Если из-за модификатора final доступа class не загружается, тогда как переменная может получить память?

    1. static final int поле static final int – это константа времени компиляции, и ее значение жестко закодировано в целевом classе без ссылки на его начало;
    2. поэтому ваш основной class не вызывает загрузку classа, содержащего поле;
    3. поэтому статический инициализатор в этом classе не выполняется.

    В частности, скомпилированный байт-код соответствует этому:

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

    Как только вы удаляете final , он больше не является константой времени компиляции, и описанное выше особое поведение не применяется. Класс Mno загружается, как вы ожидаете, и выполняет его статический инициализатор.

    Причина, по которой class не загружен, заключается в том, что VAL является final и инициализируется константным выражением (9090). Если и только если эти два условия выполнены, константа оценивается во время компиляции и «жестко запрограммирована» там, где это необходимо.

    Чтобы предотвратить вычисление выражения во время компиляции (и чтобы JVM загрузил ваш class), вы можете:

    • удалить ключевое слово final:

       static int VAL = 9090; //not a constant variable any more 
    • или изменить выражение правой стороны на что-то не постоянное (даже если переменная остается окончательной):

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

    Если вы видите сгенерированный байт-код с использованием javap -v Test.class , main () javap -v Test.class следующим образом:

     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 

    В « 11: sipush 9090 » вы можете четко видеть, что статическое конечное значение напрямую используется, потому что Mno.VAL – это постоянная времени компиляции. Поэтому не требуется загружать class Mno. Следовательно, статический блок Mno не выполняется.

    Вы можете выполнить статический блок, вручную загрузив Mno, как показано ниже:

     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) На самом деле, вы не расширили этот class Mno, поэтому при запуске компиляции он будет генерировать константу переменной VAL и когда выполнение начнется, когда эта переменная понадобится, ее загрузка из памяти. Также не требуется ваша ссылка на class, чтобы статический bock не выполнялся ,

    2) если class A расширяет этот class Mno в то время, если статический блок включен в class A, если вы это сделаете, тогда выполняется статический блок. например. public class A расширяет 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); } } 

    Насколько я знаю, он будет выполнен в порядке появления. Например :

      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"; } } 

    распечатает

      trace init1 trace middle trace init2 

    Я просто протестировал его, и статика инициализируется (=> печать), когда class «Статика» фактически используется и «выполняется» в другом fragmentе кода (в моем случае я сделал «новую Statique ()».

    Interesting Posts

    Изменение громкости звука Windows с помощью командной строки

    Как изменить уровень регистрации maven для отображения только предупреждений и ошибок?

    Как ограничить скорость канала под linux?

    Проверка жесткого диска с использованием инструментов dd и md5sum

    Как получить идентификатор задачи карты в Spark?

    Каков самый простой способ parsingа INI-файла на Java?

    Участок внутри цикла в MATLAB

    Есть ли способ получить идентификатор автоинкремента из подготовленного оператора

    Поддержка SVG на Android

    Где хранить скрипты bash, которые все пользователи могут выполнять на Debian?

    Как я могу избежать проверки хоста SSH для известных хостов?

    OkHttp Library – NetworkOnMainThreadException при простой записи

    «Windows не удалось запустить 0xc00000e» для дискового диска Windows 7 с двумя разделами Windows 7

    Установка DPI отдельных приложений в Windows

    «Text-decoration» и псевдоэлемент «: after», пересмотренный

    Давайте будем гением компьютера.