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