Синглтон через enum-путь ленивый инициализирован?
Это очень распространенный одноэлементный код перечисления:
public enum enumClazz{
INSTANCE
enumClazz(){
//do something
}
}
и множество мест сказали, что это ленивая инициализация. Но я смущен после того, как прочитал главу 7 " Внутри виртуальной машины Java '- Время жизни типа:
Спецификация виртуальной машины Java предоставляет реализации гибкость в выборе времени загрузки и компоновки классов и интерфейса, но строго определяет время инициализации. Все реализации должен инициализировать каждый класс или интерфейс при его первом активном использовании. следующие шесть ситуаций квалифицируются как активное использование:
- Создается новый экземпляр класса (в байт-кодах, выполнение новой инструкции. В качестве альтернативы, посредством неявного создания, отражения, клонирования или десериализации.)
- Вызов статического метода, объявленного классом (в байт-кодах, выполнение invokestatic инструкции)
- Использование или назначение статического поля, объявленного классом или интерфейсом, за исключением статических полей, которые являются окончательными и инициализируются выражение константы времени компиляции (в байт-кодах, выполнение getstatic или putstatic)
- Вызов некоторых отражающих методов в Java API, таких как методы класса Class или классы в java.lang.reflect пакет
- Инициализация подкласса класса (инициализация класса требует предварительной инициализации его суперкласса.)
- Обозначение класса как исходного класса (с помощью метода main() <) при запуске виртуальной машины Java
Третья точка с жирным стилем уточняет, что если поле static final
, инициализация поля происходит во время компиляции. Аналогично, INSTANCE
в enumClazz
неявно равен public static final
и соответствует третьей точке.
Может ли кто-то исправить меня, если мое понимание неверно?
Ответы
Ответ 1
enum
поля экземпляра не инициализируются выражением постоянной времени компиляции. Oни
не может быть, потому что only String
и примитивные типы являются возможными типами для выражения константы времени компиляции.
Это означает, что класс будет инициализирован при первом обращении INSTANCE
(что является точно желаемым эффектом).
Исключение в жирном тексте выше существует, потому что те константы (static final
, инициализированные выражением константы времени компиляции) будут эффективно включены во время компиляции:
class A {
public static final String FOO = "foo";
static {
System.out.println("initializing A");
}
}
class B {
public static void main(String[] args) {
System.out.println(A.FOO);
}
}
Выполнение класса B
в этом примере будет не инициализировать A
(и не будет печатать "инициализация A" ). И если вы посмотрите на байт-код, сгенерированный для B
, вы увидите строковый литерал со значением "foo" и никакой ссылкой на класс A
.
Ответ 2
Третья точка с жирным стилем уточняет, что если поле является "статическим окончанием", то инициализация поля происходит в режиме согласования
Не совсем - это относится только к "статическим полям, которые являются окончательными и инициализируются выражением постоянной времени компиляции":
static final String = "abc"; //compile time constant
static final Object = new Object(); //initialised at runtime
В вашем случае синглтон будет инициализирован, когда загружается класс перечисления, т.е. в первый раз enumClazz
указывается в вашем коде.
Таким образом, это эффективно лениво, если у вас нет инструкции где-то в вашем коде, например, например, что бы излишне инициализировать ваш синглтон как часть процесса загрузки класса:
Class<?> c = enumClazz.class;