Подтвердить что ты не робот

Статический блок не вызывается

Кто может объяснить, что происходит?

public class MagicFinal {

    public static void main(String[] args) {
        System.out.println(A.s);
    }
}

class A {
    static {
        System.out.println("class has been loaded");
    }

    public static final String s = "final";

    public static final Integer i = 3;


}

Консоль:

конечная

Что это? Я не понимаю, почему класс не был загружен, я знаю, что классы всегда загружаются при первом вызове. Поле s находится в пуле строки, я вижу, что последний модификатор является магическим.

Если я удалю последний модификатор (public static String s = "final"), я получу

Консоль:

был загружен

конечная

Примечание. Я изменил поле i: public static final int i = 3; и покажу его в консоли. Я получил то же самое, что и в ситуации String. Почему?

4b9b3361

Ответ 1

"final" является строковым литералом и как таковой является выражением константы времени компиляции. Значение переменной static final, инициализированное выражением постоянной времени компиляции, напрямую жестко кодируется в класс, который ссылается на него, и ссылка на исходный класс не делается. Поэтому инициализация исходного класса не происходит.

В качестве бокового пункта обратите внимание на различие между загрузкой классов и инициализацией класса: только последнее вхождение точно определено JLS. Загрузка классов может произойти в любое время.

Ответ 2

Это то, что написано в спецификации языка Java {8.3.2.1 Инициализаторы для переменных класса}. Это должно ответить на ваш вопрос.

Одна тонкость заключается в том, что во время выполнения статические переменные, которые являются окончательными, и что инициализируются значениями константы времени компиляции, сначала инициализируются. Это также применяется к таким полям в интерфейсах (§9.3.1). Эти переменные являются "константами", которые никогда не будет иметь начальных значений по умолчанию (§4.12.5), даже коварными программы. См. § 12.4.2 и § 13.4.9 для более подробного обсуждения.