什么时候计算枚举变量中的函数?

时间:2019-10-21 09:08:58

标签: java enums compilation runtime

考虑以下代码:

public enum MyOwnEnum    {

    JANVIER("janvier", "3101"),
    FEVRIER("février", new DateCalculator().getLeapYear()),
    MARS("mars", "3103"),
    AVRIL("avril", "3004");

    // Two variables, the protected constructor, getters

}

代码的行为如何?该方法是在编译时直接计算并固定的,还是在有人通过FEVRIERMyOwnEnum.FEVRIER调用MyOwnEnum.valueOf("FEVRIER")时计算?还是固定的,但是在运行时?

2 个答案:

答案 0 :(得分:4)

枚举常量在运行时或更具体地讲在类加载时创建一次。

考虑以下代码:

apt-get install build-essential

这将产生以下输出:

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
    }
}

请注意,这些值在后续调用中不会更改。

答案 1 :(得分:2)

如果查看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(的对象,并在其初始化静态变量FEVRIER 并维护静态变量的所有属性时调用getLeapYear()

  
      
  1. 属于该类而不属于对象(实例)的静态变量
  2.   
  3. 静态变量在执行开始时仅初始化一次。
  4.   
  5. 将首先初始化静态变量,然后再初始化任何实例变量
  6.   
  7. 该类的所有实例共享的单个副本
  8.   
  9. 可以通过类名称直接访问静态变量,并且不需要任何对象。
  10.   

由于FEVRIER是静态变量public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear()));,因此每个类加载器加载该类后,这些代码行仅执行一次。

这是供参考的字节码:

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