Enum类型中静态块的执行顺序w.r.t到构造函数

Posted

技术标签:

【中文标题】Enum类型中静态块的执行顺序w.r.t到构造函数【英文标题】:Execution order of of static blocks in an Enum type w.r.t to constructor 【发布时间】:2012-07-31 09:06:08 【问题描述】:

这是来自 Effective Java:

// Implementing a fromString method on an enum type
  private static final Map<String, Operation> stringToEnum
      = new HashMap<String, Operation>();

  static  // Initialize map from constant name to enum constant
    for (Operation op : values())
      stringToEnum.put(op.toString(), op);
  

  // Returns Operation for string, or null if string is invalid
  public static Operation fromString(String symbol) 
    return stringToEnum.get(symbol);
  

请注意,操作常量被放入 stringToEnum 映射 来自在创建常量后运行的静态块。 试图让每一个常数把自己从自己的地图中放入 构造函数会导致编译错误。这是好事, 因为如果它是合法的,它将导致 NullPointerException。枚举 不允许构造函数访问枚举的静态字段, 除了编译时常量字段。这个限制是必要的 因为这些静态字段还没有被初始化时 构造函数运行。

我的问题是关于这条线的:

"请注意,Operation 常量被放入 stringToEnum 映射中 来自在创建常量后运行的静态块”。

我认为静态块在构造函数运行之前被执行。它们实际上是在类加载期间执行的。

我在这里错过了什么?

【问题讨论】:

见***.com/questions/3028219/… 【参考方案1】:

Operation 常量是在静态块中按出现顺序创建的静态字段。

static  
    // instantiate enum instances here
    ...
    // Initialize map from constant name to enum constant     
    for (Operation op : values())       
       stringToEnum.put(op.toString(), op);   
 

【讨论】:

【参考方案2】:

static 块按出现顺序执行(您可以有多个静态块),当类加载器加载类时,例如。它在构造函数之前运行。

【讨论】:

【参考方案3】:

我将您的问题理解为:为什么保证枚举常量将在静态块运行之前被初始化。答案在JLS给出,具体例子在#8.9.2.1给出,解释如下:

静态初始化从上到下发生。

枚举常量是隐式的 final static 并且在静态初始化块之前声明。

编辑

行为与普通类没有什么不同。下面的代码打印出来:

In constructor: PLUS
PLUS == null MINUS == null

In constructor: MINUS
PLUS != null MINUS == null

In static initialiser
PLUS != null MINUS != null

In constructor: after static
PLUS != null MINUS != null
public class Operation 

    private final static Operation PLUS = new Operation("PLUS");
    private final static Operation MINUS = new Operation("MINUS");

    static 
        System.out.println("In static initialiser");
        System.out.print("PLUS = " + PLUS);
        System.out.println("\tMINUS = " + MINUS);
    

    public Operation(String s) 
        System.out.println("In constructor: " + s);
        System.out.print("PLUS = " + PLUS);
        System.out.println("\tMINUS = " + MINUS);
    

    public static void main(String[] args) 
        Operation afterStatic = new Operation ("after static");
        

【讨论】:

说 Operation 代表 Calculator 的操作。并且常量(PLUS,MINUS,DIVIDE,MULTIPLY)只会在构造函数运行后创建。所以我很困惑如何在构造函数运行之前初始化常量。保存常量的隐式静态最终字段可以在构造函数之前创建,但它们只能在构造函数运行之后分配。 每个常量(加号、减号...)将在其各自的构造函数运行后被初始化。如果需要,执行顺序将是:PLUS = new Operation(...); MINUS = new Operation(...); ... ; static block 这就是为什么 Bloch 说如果你尝试从构造函数填充映射,因为直到所有构造函数都完成运行后才会初始化常量。 所以构造函数实际上在静态块之前运行。这意味着枚举行为与其他普通类是分开的。对吧? 不,不是 - 我在我的答案中添加了一个普通类的示例。枚举以类似的方式运行,只是其中一些是隐式的。

以上是关于Enum类型中静态块的执行顺序w.r.t到构造函数的主要内容,如果未能解决你的问题,请参考以下文章

子类继承父类,那么各代码块的执行顺序为:

一道面试题:静态代码块的执行顺序

Java中静态代码块构造代码块构造函数普通代码块(转载)

构造函数,构造代码块和静态代码块的先后顺序和运用

java-普通代码块构造代码块和静态代码块的区别。

java静态代码块,构造方法,构造代码块的执行先后顺序