Почему статические и экземплярные блоки init в Enums ведут себя не так, как в классах

При изучении сертификационного теста Java я узнал, что статические блоки инициализации запускаются один раз при загрузке класса, в порядке появления в исходном коде, что блоки инициализации экземпляра запускаются каждый раз, когда создается экземпляр, и этот код в конструкторах запускается каждый раз после этого создается экземпляр. Чтобы проверить это, я создал класс с некоторыми статическими блоками и блоками инициализации экземпляра, а также конструктор с материалами для печати. Все работало как ожидалось - за исключением того, что я думал, что "загруженный" имел в виду только во время выполнения, но я предполагаю, что это происходит при создании первого экземпляра, поскольку я вообще не получаю никакого вывода, если не создаю хотя бы 1 экземпляр класса. Затем я попробовал то же самое с enum, и заказ был полностью отменен. Во-первых, блоки инициализации запускаются один раз для каждого значения, которое имеет перечисление, когда на перечисление впервые ссылаются в коде, во-вторых, блоки инициализации отмечены как статические, после того, что я предположил, было блоками инициализации экземпляра! Это противоположно тому, что я ожидал. Вот разбивка моих вопросов.

  1. Почему блоки init, помеченные как static, запускаются последними в перечислении?
  2. Может ли перечисление иметь блоки инициализации экземпляра?
  3. Почему блоки, которые я считал экземплярами init, запускаются только один раз при загрузке enum, а не каждый раз, когда ссылаются на новое значение enum?
  4. Статические блоки инициализации класса запускаются, когда класс "загружен". Что значит загруженный? Происходит ли это только один раз, когда объект создается в классе?

Спасибо! Это очень смущает меня.

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
Другие вопросы по тегам