Why can't enum's constructor access static fields?
Solution 1:
The constructor is called before the static fields have all been initialized, because the static fields (including those representing the enum values) are initialized in textual order, and the enum values always come before the other fields. Note that in your class example you haven't shown where ABBREV_MAP is initialized - if it's after SUNDAY, you'll get an exception when the class is initialized.
Yes, it's a bit of a pain and could probably have been designed better.
However, the usual answer in my experience is to have a static {}
block at the end of all the static initializers, and do all static initialization there, using EnumSet.allOf
to get at all the values.
Solution 2:
Quote from JLS, section "Enum Body Declarations":
Without this rule, apparently reasonable code would fail at run time due to the initialization circularity inherent in enum types. (A circularity exists in any class with a "self-typed" static field.) Here is an example of the sort of code that would fail:
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); Color() { colorMap.put(toString(), this); } }
Static initialization of this enum type would throw a NullPointerException because the static variable colorMap is uninitialized when the constructors for the enum constants run. The restriction above ensures that such code won’t compile.
Note that the example can easily be refactored to work properly:
enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); static { for (Color c : Color.values()) colorMap.put(c.toString(), c); } }
The refactored version is clearly correct, as static initialization occurs top to bottom.