什么时候计算枚举变量中的函数?
When are computed the functions inside an Enum's variable?
考虑以下代码:
public enum MyOwnEnum {
JANVIER("janvier", "3101"),
FEVRIER("février", new DateCalculator().getLeapYear()),
MARS("mars", "3103"),
AVRIL("avril", "3004");
// Two variables, the protected constructor, getters
}
代码的行为如何?该方法是在编译时直接计算并固定,还是会在每次有人通过 MyOwnEnum.FEVRIER
或 MyOwnEnum.valueOf("FEVRIER")
调用 FEVRIER
时计算?或者固定的,但在运行时?
枚举常量在运行时创建一次,或者更具体地说,在 class 加载时创建。
考虑以下代码:
public enum TestEnum {
ONE("One at " + System.nanoTime()),
TWO("Two at " + System.nanoTime());
String value;
TestEnum(String value) {
System.out.println(value);
this.value = value;
}
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println("Loading");
Class.forName("TestEnum"); // Load class
System.out.println("Evaluating");
System.out.println(TestEnum.ONE.value); // Evaluate value one
System.out.println(TestEnum.TWO.value); // Evaluate value two
}
}
这会生成以下输出:
Loading
One at 31207575500045
Two at 31207575625697
Evaluating
One at 31207575500045
Two at 31207575625697
请注意,这些值不会在后续调用中更改。
如果您查看 ENUM
生成的字节码,您会发现上面的代码与下面的代码类似:
class MyOwnEnum{
public static MyOwnEnum JANVIER = new MyOwnEnum("janvier", "3101");
public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));
public static MyOwnEnum MARS = new MyOwnEnum("mars", "3103");
}
这意味着您的代码将创建 DateCalculator(
) 的对象并调用 getLeapYear()
时它将 初始化静态变量 FEVRIER 并维护所有属性静态变量:
- A static variable which belongs to the class and not to object(instance)
- Static variables are initialized only once , at the start of the execution.
- Static variables will be initialized first, before the initialization of any instance variables
- A single copy to be shared by all instances of the class
- A static variable can be accessed directly by the class name and doesn’t need any object.
因为 FEVRIER
是一个静态变量 public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));
这行代码将只在每个 class 加载器加载 class 时执行一次。
这里是字节码供参考:
21: ldc #26 // String FEVRIER
23: iconst_1
24: ldc #27 // String fΘvrier
26: new #29 // class com/java8/demo/DateCalculator
29: dup
30: invokespecial #31 // Method com/java8/demo/DateCalculator."<init>":()V
33: invokevirtual #33 // Method com/java8/demo/DateCalculator.getLeapYear:()Ljava/lang/String;
36: invokespecial #20 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
39: putstatic #37 // Field FEVRIER:Lcom/java8/demo/MyOwnEnum;
42: new #1 // class com/java8/demo/MyOwnEnum
45: dup
46: ldc #39 // String MARS
48: iconst_2
49: ldc #40 // String mars
51: ldc #42 // String 3103
53: invokespecial #20 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
56: putstatic #44 // Field MARS:Lcom/java8/demo/MyOwnEnum;
59: new #1 // class com/java8/demo/MyOwnEnum
考虑以下代码:
public enum MyOwnEnum {
JANVIER("janvier", "3101"),
FEVRIER("février", new DateCalculator().getLeapYear()),
MARS("mars", "3103"),
AVRIL("avril", "3004");
// Two variables, the protected constructor, getters
}
代码的行为如何?该方法是在编译时直接计算并固定,还是会在每次有人通过 MyOwnEnum.FEVRIER
或 MyOwnEnum.valueOf("FEVRIER")
调用 FEVRIER
时计算?或者固定的,但在运行时?
枚举常量在运行时创建一次,或者更具体地说,在 class 加载时创建。
考虑以下代码:
public enum TestEnum {
ONE("One at " + System.nanoTime()),
TWO("Two at " + System.nanoTime());
String value;
TestEnum(String value) {
System.out.println(value);
this.value = value;
}
}
public class Test {
public static void main(String[] args) throws Exception {
System.out.println("Loading");
Class.forName("TestEnum"); // Load class
System.out.println("Evaluating");
System.out.println(TestEnum.ONE.value); // Evaluate value one
System.out.println(TestEnum.TWO.value); // Evaluate value two
}
}
这会生成以下输出:
Loading
One at 31207575500045
Two at 31207575625697
Evaluating
One at 31207575500045
Two at 31207575625697
请注意,这些值不会在后续调用中更改。
如果您查看 ENUM
生成的字节码,您会发现上面的代码与下面的代码类似:
class MyOwnEnum{
public static MyOwnEnum JANVIER = new MyOwnEnum("janvier", "3101");
public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));
public static MyOwnEnum MARS = new MyOwnEnum("mars", "3103");
}
这意味着您的代码将创建 DateCalculator(
) 的对象并调用 getLeapYear()
时它将 初始化静态变量 FEVRIER 并维护所有属性静态变量:
- A static variable which belongs to the class and not to object(instance)
- Static variables are initialized only once , at the start of the execution.
- Static variables will be initialized first, before the initialization of any instance variables
- A single copy to be shared by all instances of the class
- A static variable can be accessed directly by the class name and doesn’t need any object.
因为 FEVRIER
是一个静态变量 public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));
这行代码将只在每个 class 加载器加载 class 时执行一次。
这里是字节码供参考:
21: ldc #26 // String FEVRIER
23: iconst_1
24: ldc #27 // String fΘvrier
26: new #29 // class com/java8/demo/DateCalculator
29: dup
30: invokespecial #31 // Method com/java8/demo/DateCalculator."<init>":()V
33: invokevirtual #33 // Method com/java8/demo/DateCalculator.getLeapYear:()Ljava/lang/String;
36: invokespecial #20 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
39: putstatic #37 // Field FEVRIER:Lcom/java8/demo/MyOwnEnum;
42: new #1 // class com/java8/demo/MyOwnEnum
45: dup
46: ldc #39 // String MARS
48: iconst_2
49: ldc #40 // String mars
51: ldc #42 // String 3103
53: invokespecial #20 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V
56: putstatic #44 // Field MARS:Lcom/java8/demo/MyOwnEnum;
59: new #1 // class com/java8/demo/MyOwnEnum