hvgotcodes
hvgotcodes

Reputation: 120188

Creating new instance of class inside enum constructor when enum is in the class

Initially I thought I would have a chicken and egg problem here, but exploring this in a unit test doesn't indicate any problems. I want to understand what is going on here. I would have thought that since enums are static and final the MyEnum constructor would run when the JVM loads MyClass. However in my test it prints "getValue" before "MyEnum constructor".

MyClass {

   private enum MyEnum {
       VALUE;

       MyEnum() {
          System.out.println("MyEnum constructor");
          MyClass clazz = new MyClass(); 
       }
   }

   public MyEnum getValue() {
      System.out.println("getValue");
      return MyEnum.VALUE;
   }

}

public class MyClassTest {

    @Test
    public void testStuff() {
        MyClass clazz = new MyClass();
        clazz.getValue();
    }
}

Upvotes: 1

Views: 633

Answers (1)

Savior
Savior

Reputation: 3531

The fact that a class/interface/enum/annotation is nested within another class does not affect when its initialization will occur.

The rules for initialization apply regardless. They are defined in the JLS here.

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • A static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).

The JLS also says the following about enum types

An enum declaration specifies a new enum type, a special kind of class type.

And about its members, it says

For each enum constant c declared in the body of the declaration of E, E has an implicitly declared public static final field of type E that has the same name as c. The field has a variable initializer which instantiates E and passes any arguments of c to the constructor chosen for E. The field has the same annotations as c (if any).

Put all this together and you get an explanation for the behavior you see.

Your code instantiates MyClass, then invokes its getValue() method. getValue() prints something to standard out and then tries to access a static field declared by MyEnum. This triggers initialization of the enum type, which initializes the public static static VALUE field, which invokes the corresponding MyEnum construct that again prints to standard out.

Upvotes: 1

Related Questions