java 枚举 - 静态和实例块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11419519/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:02:35  来源:igfitidea点击:

Enums - static and instance blocks

javaenumsstatic-block

提问by NINCOMPOOP

I had learned that in Java the static block gets executed when the class is initialized and instance block get executed before the construction of each instance of the class . I had always seen the static block to execute before the instance block . Why the case is opposite for enums?

我了解到在 Java 中,静态块在类初始化时执行,实例块在类的每个实例构建之前执行。我一直看到静态块在实例块之前执行。为什么情况相反enums

Can anyone please explain me the output of the sample code :

任何人都可以向我解释示例代码的输出:

enum CoffeeSize {

    BIG(8), LARGE(10),HUGE(12),OVERWHELMING();
    private int ounces ;

    static {
        System.out.println("static block ");
    }
    {
        System.out.println("instance block");
    }

    private CoffeeSize(int ounces){
        this.ounces = ounces;
        System.out.println(ounces);
    }
    private CoffeeSize(){
        this.ounces = 20;
        System.out.println(ounces);
    }

    public int getOunces() {
        return ounces;
    }
} 

Output:

输出:

instance block
8
instance block
10
instance block
12
instance block
20
static block

实例块
8
实例块
10
实例块
12
实例块
20
静态块

采纳答案by Pshemo

You need to know that enum values are static fields which hold instances of that enum type, and initialization order of static fields depends on their position. See this example

您需要知道枚举值是包含该枚举类型实例的静态字段,并且静态字段的初始化顺序取决于它们的位置。看这个例子

class SomeClass{
    public SomeClass() { System.out.println("creating SomeClass object"); }
}

class StaticTest{
    static{ System.out.println("static block 1"); }
    static SomeClass sc = new SomeClass();
    static{ System.out.println("static block 2"); }

    public static void main(String[] args) {
        new StaticTest();
    }
}

output

输出

static block 1
creating SomeClass object
static block 2

Now since enum values are always placed at start of enum type, they will always be called before any static initialization block, because everything else can only be declared after enum values.
BUT initialization of enum values (which happens at class initialization) their constructors are called and as you said non-static initialization blocks are executed at start of every constructor which is why you see them:

现在,由于枚举值始终位于枚举类型的开头,因此它们将始终在任何静态初始化块之前调用,因为其他所有内容只能在枚举值之后声明。
但是枚举值的初始化(发生在类初始化时)它们的构造函数被调用,正如你所说的,非静态初始化块在每个构造函数的开头执行,这就是你看到它们的原因:

  • for every enum value
  • and before any static initialization block.
  • 对于每个枚举值
  • 在任何静态初始化块之前。

回答by Wolfram

Little late and building up on Pshemo's answer. The output of the (compiling) code below is as follows:

有点晚了,并建立了Pshemo 的回答。下面(编译)代码的输出如下:

8
10
Foo
static block 
Bar

So the enum constant initializations are executed first (as Pshemo said, they are always implicitly staticand final, see second blockquote) and then all fields explicitly declared as staticare initialized. As mentioned, the language specification says this about the order of execution during class initialization and about enum constants:

因此,首先执行枚举常量初始化(如 Pshemo 所说,它们总是隐式staticfinal,请参阅第二个块引用),然后static初始化所有显式声明为的字段。如前所述,语言规范说明了类初始化期间的执行顺序和枚举常量:

Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

In addition to the members that an enum type E inherits from Enum, for each declared enum constant with the name n, the enum type has an implicitly declared public static final field named n of type E. These fields are considered to be declared in the same order as the corresponding enum constants, before any static fields explicitly declared in the enum type.

接下来,按文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。

除了枚举类型 E 从 Enum 继承的成员之外,对于每个名为 n 的声明的枚举常量,枚举类型都有一个隐式声明的名为 n 的类型 E 的公共静态最终字段。在枚举类型中显式声明的任何静态字段之前,这些字段被视为以与相应枚举常量相同的顺序声明。



class StaticTest {
    enum CoffeeSize {
        BIG(8), LARGE(10);
        private int ounces;

        static Foo foo = new Foo();
        static { System.out.println("static block "); }
        static Bar bar = new Bar();

        private CoffeeSize(int ounces){
            this.ounces = ounces;
            System.out.println(ounces);
        }
    }
    public static void main(String[] args) {
        CoffeeSize cs = CoffeeSize.LARGE;
    }
}

class Foo { public Foo() { System.out.println("Foo"); } }
class Bar { public Bar() { System.out.println("Bar"); } }

回答by Yanhui Zhou

Use bytecode to make out this problem.

使用字节码来解决这个问题。

import java.util.ArrayList;
import java.util.List;

public enum EnumDemo {
    ONE(1), TWO(2);

    private final static List<Integer> vals;
    static {
        System.out.println("fetch instance from static");
        vals = new ArrayList<>();
        EnumDemo[] values = EnumDemo.values();
        for (EnumDemo value : values) {
            vals.add(value.val);
        }
    }

    private int val;
    EnumDemo(int val){
        this.val = val;
        System.out.println("create instance:" + val);
    }

}

use javac compile to class file, and then javap -c EnumDemo.class, got this:

使用 javac 编译成类文件,然后javap -c EnumDemo.class,得到这个:

Compiled from "EnumDemo.java"
public final class EnumDemo extends java.lang.Enum<EnumDemo> {
  public static final EnumDemo ONE;

  public static final EnumDemo TWO;

  public static EnumDemo[] values();
    Code:
       0: getstatic     #1                  // Field $VALUES:[LEnumDemo;
       3: invokevirtual #2                  // Method "[LEnumDemo;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[LEnumDemo;"
       9: areturn       

  public static EnumDemo valueOf(java.lang.String);
    Code:
       0: ldc_w         #4                  // class EnumDemo
       3: aload_0       
       4: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       7: checkcast     #4                  // class EnumDemo
      10: areturn       

  static {};
    Code:
       0: new           #4                  // class EnumDemo
       3: dup           
       4: ldc           #16                 // String ONE
       6: iconst_0      
       7: iconst_1      
       8: invokespecial #17                 // Method "<init>":(Ljava/lang/String;II)V
      11: putstatic     #18                 // Field ONE:LEnumDemo;
      14: new           #4                  // class EnumDemo
      17: dup           
      18: ldc           #19                 // String TWO
      20: iconst_1      
      21: iconst_2      
      22: invokespecial #17                 // Method "<init>":(Ljava/lang/String;II)V
      25: putstatic     #20                 // Field TWO:LEnumDemo;
      28: iconst_2      
      29: anewarray     #4                  // class EnumDemo
      32: dup           
      33: iconst_0      
      34: getstatic     #18                 // Field ONE:LEnumDemo;
      37: aastore       
      38: dup           
      39: iconst_1      
      40: getstatic     #20                 // Field TWO:LEnumDemo;
      43: aastore       
      44: putstatic     #1                  // Field $VALUES:[LEnumDemo;
      47: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      50: ldc           #21                 // String fetch instance from static
      52: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      55: new           #22                 // class java/util/ArrayList
      58: dup           
      59: invokespecial #23                 // Method java/util/ArrayList."<init>":()V
      62: putstatic     #24                 // Field vals:Ljava/util/List;
      65: invokestatic  #25                 // Method values:()[LEnumDemo;
      68: astore_0      
      69: aload_0       
      70: astore_1      
      71: aload_1       
      72: arraylength   
      73: istore_2      
      74: iconst_0      
      75: istore_3      
      76: iload_3       
      77: iload_2       
      78: if_icmpge     109
      81: aload_1       
      82: iload_3       
      83: aaload        
      84: astore        4
      86: getstatic     #24                 // Field vals:Ljava/util/List;
      89: aload         4
      91: getfield      #7                  // Field val:I
      94: invokestatic  #26                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      97: invokeinterface #27,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     102: pop           
     103: iinc          3, 1
     106: goto          76
     109: return        
}

So, enum instance is the static instance, and at the head.

因此,枚举实例是静态实例,并且位于头部。

回答by Kumar Vivek Mitra

1.An enum type is a type whose fields consist of a fixed set of constants. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

1.一种枚举类型是一种类型,其字段包括一组固定的常数的。常见示例包括罗盘方向(北、南、东和西的值)和一周中的几天。

2.They are static final constant, therefore have all letters in Caps.

2.它们是静态最终常量,因此所有字母都为大写字母。

3.And static variables are initialized as soon as the JVM loads the class.

3.JVM 一加载类就初始化静态变量。

For further details see this link:

有关更多详细信息,请参阅此链接:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html

http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html