为什么Enums中的静态和实例init块的行为与Classes中的不同

时间:2013-12-16 20:09:13

标签: java enums initialization scjp open-closed-principle

在学习Java认证测试时,我了解到静态初始化块在加载类时按照源代码中的外观顺序运行一次,每次创建实例时运行实例初始化块,并在构造函数中运行该代码每次在此之后创建实例时运行。为了测试我创建了一个带有一些静态和实例初始化块的类以及一个带有打印内容的构造函数。一切都按预期工作 - 除了我认为“加载”意味着只是在运行时,但我想它发生在第一个实例创建时,因为我根本没有得到任何输出,除非我创建至少1个类的实例。然后我用enum尝试了同样的命令并且命令全部关闭。首先,初始化块对枚举在代码中首次引用时枚举所具有的每个值运行一次,其次是在我假设为实例初始化块之后标记为静态的init块!这与我的预期相反。以下是我的问题细分。

  1. 为什么标记为static的init块在枚举中最后运行?
  2. 枚举可以有实例初始化块吗?
  3. 为什么我认为实例初始化块的块只在加载枚举时运行一次而不是每次引用新的枚举值时都会运行?
  4. 类“静态”初始化块在“加载”类时运行。加载是什么意思?当一个对象在类中实例化时,它只发生一次吗?
  5. 谢谢!这让我非常困惑。

    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"); }  
    }
    

1 个答案:

答案 0 :(得分:8)

Java Language Specification says this about enum constants

  

除了Enum类型E继承自Enum的成员之外,   对于每个声明的枚举常量,名称为n,枚举类型为   隐式声明了名为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阻止之前得到评估。

  

为什么标记为static的init块在枚举中最后运行?

见上文。

  

枚举可以有实例初始化块吗?

是的,编译你的代码,你会看到。

  

为什么我认为实例初始块的块只在加载枚举时运行一次,而不是每次引用新的枚举值时都会运行?

初始化枚举类型后,将创建(实例化)枚举常量。您不会在任何时候创建新的enum

Color color = Color.RED;

您只是引用已创建的现有对象。

  

类“静态”初始化块在“加载”类时运行。加载是什么意思?当一个对象在类中实例化时,它只发生一次吗?

首次在JVM中引用类时,它由ClassLoader加载并初始化。 Read more about it here.