You have a hidden circular dependency that's confusing the JVM. Let's take a look at your code.
class Recreate {
private static ArrayList FEATURES = new ArrayList();
public enum Car {
TESLA(FEATURES);
Car(ArrayList l) { }
}
public static class Garage {
final Car car;
Garage(Car car) {
this.car = car;
}
}
public static Garage ONE_CAR_GARAGE = new Garage(Car.TESLA);
}
We'll also need a few snippets from a page out of the JLS.
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
- A static field declared by T is used and the field is not a constant variable (§4.12.4).
12.4.2. Detailed Initialization Procedure
...
- 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.
So our static data is being initialized when it's first referenced. Now, your Car.TESLA
is implicitly static final
, but it's not a constant, as per the definition.
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression
So for our purposes, there are three static non-constant variables in play here: FEATURES
, TESLA
, and ONE_CAR_GARAGE
.
Now, in your working case, you reference Recreate.ONE_CAR_GARAGE
. This is a reference to a static field in Recreate
, so FEATURES
and then ONE_CAR_GARAGE
get initialized. Then, during the initialization of ONE_CAR_GARAGE
, TESLA
gets initialized since its enumeration class is referenced. All's well.
However, if we reference the enum too early then we do things in the wrong order. Recreate.Car.TESLA
gets referenced, so TESLA
gets initialized. TESLA
references FEATURES
, so Recreate
has to be initialized. This causes FEATURES
and ONE_CAR_GARAGE
to get initialized before TESLA
finishes existing.
It's that hidden dependency that trips you up. Recreate.Car
depends on Recreate
which depends on Recreate.Car
. Moving the ONE_CAR_GARAGE
field into the Garage
class will cause it to not get initialized with FEATURES
and will fix your problem.