Почему статические и экземплярные блоки init в Enums ведут себя не так, как в классах
При изучении сертификационного теста Java я узнал, что статические блоки инициализации запускаются один раз при загрузке класса, в порядке появления в исходном коде, что блоки инициализации экземпляра запускаются каждый раз, когда создается экземпляр, и этот код в конструкторах запускается каждый раз после этого создается экземпляр. Чтобы проверить это, я создал класс с некоторыми статическими блоками и блоками инициализации экземпляра, а также конструктор с материалами для печати. Все работало как ожидалось - за исключением того, что я думал, что "загруженный" имел в виду только во время выполнения, но я предполагаю, что это происходит при создании первого экземпляра, поскольку я вообще не получаю никакого вывода, если не создаю хотя бы 1 экземпляр класса. Затем я попробовал то же самое с enum, и заказ был полностью отменен. Во-первых, блоки инициализации запускаются один раз для каждого значения, которое имеет перечисление, когда на перечисление впервые ссылаются в коде, во-вторых, блоки инициализации отмечены как статические, после того, что я предположил, было блоками инициализации экземпляра! Это противоположно тому, что я ожидал. Вот разбивка моих вопросов.
- Почему блоки init, помеченные как static, запускаются последними в перечислении?
- Может ли перечисление иметь блоки инициализации экземпляра?
- Почему блоки, которые я считал экземплярами init, запускаются только один раз при загрузке enum, а не каждый раз, когда ссылаются на новое значение enum?
- Статические блоки инициализации класса запускаются, когда класс "загружен". Что значит загруженный? Происходит ли это только один раз, когда объект создается в классе?
Спасибо! Это очень смущает меня.
public class EnumInit {
public static void main(String[] args) {
System.out.println(Color.RED.toString() + " Main");
MyInit myInit = new MyInit();
System.out.println(Color.BLUE.toString() + " Main");
MyInit mySecondInit = new MyInit();
}
}
enum Color {
RED, BLUE, GREEN;
String instanceVar = "Enum Instance Variable Text";
static { System.out.println("Enum Static init block 1"); }
{ System.out.println("Enum Instance init block 1"); }
static { System.out.println("Enum Static static init block 2"); }
Color() {
System.out.println(instanceVar);
System.out.println("Enum String Literal");
}
{ System.out.println("Enum Instance init block 2"); }
}
class MyInit {
String instanceVar = "Class Instance Variable Text";
static { System.out.println("Class Static init block 1"); }
{ System.out.println("Class Instance init block 1"); }
static { System.out.println("Class Static static init block 2"); }
MyInit() {
System.out.println(instanceVar);
System.out.println("Class String Literal");
}
{ System.out.println("Class Instance init block 2"); }
}
2 ответа
Спецификация языка Java говорит об этом enum
константы
В дополнение к членам, которые тип enum типа наследует от Enum, для каждой объявленной константы enum с именем n тип enum имеет неявно объявленное публичное статическое конечное поле с именем n типа E. Эти поля считаются объявленными в в том же порядке, что и соответствующие константы перечисления, перед любыми статическими полями, явно объявленными в типе перечисления. Каждое такое поле инициализируется соответствующей ей константой перечисления.
Так
enum Color {
RED, BLUE, GREEN;
...
}
на самом деле
public static final Color RED = new Color();
public static final Color BLUE = new Color();
public static final Color GREEN = new Color();
который будет оценен до static
блоки у вас есть.
Почему блоки init, помеченные как static, запускаются последними в перечислении?
Смотри выше.
Может ли перечисление иметь блоки инициализации экземпляра?
Да, скомпилируйте свой код, и вы увидите.
Почему блоки, которые я считал экземплярами init, запускаются только один раз при загрузке enum, а не каждый раз, когда ссылаются на новое значение enum?
Константы перечисления создаются (создаются) после инициализации типа перечисления. Вы не создаете новый enum
в любое время вы делаете
Color color = Color.RED;
Вы просто ссылаетесь на уже созданный, существующий объект.
Статические блоки инициализации класса запускаются, когда класс "загружен". Что значит загруженный? Происходит ли это только один раз, когда объект создается в классе?
Когда класс ссылается в JVM в первый раз, он загружается ClassLoader
и инициализирован. Об этом подробнее здесь.
В
enum
в
static init block
выполняется последним.
Enums
1st - instance init block
2nd - constructor block
last - static init block or any other declared static (only once and will be always last executed)
Classes
1st - static init block or any other declared static (only once, always first to be executed)
2nd - instance init block
3rd - constructor