Статический блок не вызывается
Кто может объяснить, что происходит?
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. Почему?
Ответы
Ответ 1
"final"
является строковым литералом и как таковой является выражением константы времени компиляции. Значение переменной static final
, инициализированное выражением постоянной времени компиляции, напрямую жестко кодируется в класс, который ссылается на него, и ссылка на исходный класс не делается. Поэтому инициализация исходного класса не происходит.
В качестве бокового пункта обратите внимание на различие между загрузкой классов и инициализацией класса: только последнее вхождение точно определено JLS. Загрузка классов может произойти в любое время.
Ответ 2
Это то, что написано в спецификации языка Java {8.3.2.1 Инициализаторы для переменных класса}. Это должно ответить на ваш вопрос.
Одна тонкость заключается в том, что во время выполнения статические переменные, которые являются окончательными, и что инициализируются значениями константы времени компиляции, сначала инициализируются. Это также применяется к таким полям в интерфейсах (§9.3.1). Эти переменные являются "константами", которые никогда не будет иметь начальных значений по умолчанию (§4.12.5), даже коварными программы. См. § 12.4.2 и § 13.4.9 для более подробного обсуждения.