When are computed the functions inside an Enum's variable?

Viewed 103

Consider the following code :

public enum MyOwnEnum    {

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

    // Two variables, the protected constructor, getters

}

How would the code behave ? Would the method be computed directly at compile time and fixed, or would it be computed each time someone calls FEVRIER through MyOwnEnum.FEVRIER or MyOwnEnum.valueOf("FEVRIER") ? Or fixed, but at runtime ?

2 Answers

The enum constants are created once at runtime, or more specifically, at class-loading time.

Consider the following code:

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

This generates the following output:

Loading
One at 31207575500045
Two at 31207575625697
Evaluating
One at 31207575500045
Two at 31207575625697

Note that the values don't change on subsequent invocations.

If you look at the byte code generated by your ENUM you can see that the above code is similar as below code:

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

That means your code will create the Object of DateCalculator() and call getLeapYear() when it will init the static variable FEVRIER and maintain all properties of static variable:

  1. A static variable which belongs to the class and not to object(instance)
  2. Static variables are initialized only once , at the start of the execution.
  3. Static variables will be initialized first, before the initialization of any instance variables
  4. A single copy to be shared by all instances of the class
  5. A static variable can be accessed directly by the class name and doesn’t need any object.

As FEVRIER is a static variable public static MyOwnEnum FEVRIER = new MyOwnEnum(("février", new DateCalculator().getLeapYear())); this lines of code will execute only once per class loader loaded the class.

Here is the byte code for reference:

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
Related