I'm developing a LALG compiler to my college course on Java 1.6. So I did a types class and grammar class.
EnumTypes
public enum EnumTypes {
A("OLA"),
B("MUNDO"),
C("HELLO"),
D("WORLD"),
/**
* The order below is reversed on purpose.
* Revert it and will you get a NULL list of types furder.
*/
I(EnumGrammar.THREE),
H(EnumGrammar.TWO),
F(EnumGrammar.ONE),
E(EnumGrammar.ZERO);
private String strValue;
private EnumGrammar enumGrammarValue;
private EnumTypes(String strValue) {
this.strValue = strValue;
}
private EnumTypes(EnumGrammar enumGrammarValue) {
this.enumGrammarValue = enumGrammarValue;
}
public String getStrValue() {
return strValue;
}
public EnumGrammar getEnumTiposValue() {
return enumGrammarValue;
}
}
EnumGrammar
public enum EnumGrammar {
ZERO(EnumTypes.A,EnumTypes.B,EnumTypes.F,EnumTypes.D),
ONE(EnumTypes.C),
TWO(EnumTypes.B,EnumTypes.H),
THREE(EnumTypes.D,EnumTypes.A,EnumTypes.C);
private EnumTypes[] values;
private EnumGrammar(EnumTypes ... values) {
this.values = values;
}
public EnumTypes[] getValues() {
return values;
}
}
When I call EnumTypes.E.getEnumTiposValue().getValues()
where are supposed to be the EnumTypes.F
value is NULL.
Main
public class Main {
public static void main(String[] args) {
//prints [A, B, null, D]
System.out.println(Arrays.toString(EnumTypes.E.getEnumTiposValue().getValues()));
}
}
There are a workaround or something like that?
Thanks!
An enum can be null. When an enum (like Color in this program) is a field of a class, it is by default set to null.
It is an Object representing a defined state. Think of it like an static final Object which can't be changed after intialization, but easyly compared. So what you can do is check on null and on Equals to your existing Enum Values.
An enum value cannot be null. It is a value type like an int. To avoid the "cannot convert null" error, use a special None constant as the first enum item.
If you want to represent null with an enum, then you'll have to explicit this by using a null object pattern manually with a NONE value and a custom implementation for prettyPrint() based on NONE value.
Essentially, it is always a very risky thing to allow a reference to an object to get outside of the class before the class is fully constructed, that is before the constructor is finished. Enums are singletons. Here you have two classes whose constructors receive each other's instances in a circular dependency. Add to this that class loading is lazy, so the classes will be loaded and enum instances created as you go and it sounds quite reasonable that the ends result depends on the order in which the enums are initialized.
I can't quote the corresponding point from JLS right now (I'll look for it), but I believe that if you allow a reference to an object to "leave the class" from outside of the constructor (which happens here due to enums being singletons initialized by the JVM), the JVM is free to do something strange.
EDIT: these points from the JLS are of importance for the case:
A read of a final field of an object within the thread that constructs that object is ordered with respect to the initialization of that field within the constructor by the usual happens-before rules. If the read occurs after the field is set in the constructor, it sees the value the final field is assigned, otherwise it sees the default value.
Since enum values are internally treated like static final fields (see 16.5 below), if you reference one enum from inside the constructor of another enum whose constructor references the first one, at least one of these two objects will not yet have been fully initialized and so the reference may still be null at this point.The definite assignment/unassignment status of any construct within the class body of an enum constant is governed by the usual rules for classes
Here is what's happening, in order:
EnumTypes.E.getEnumTiposValue()
, triggering class loading of EnumTypes
.EnumTypes
begins - its enum constants will be initialized in the order they're declared.EnumTypes.A
through EnumTypes.D
are initialized.EnumTypes.I
begins initialization - its constructor call references EnumGrammar.THREE
, triggering class loading of EnumGrammar
.EnumGrammar
begins - its enum constants will be initialized in the order they're declared.EnumGrammar.ZERO
is initialized - its constructor call references EnumTypes.A
, EnumTypes.B
, EnumTypes.F
, and EnumTypes.D
. Out of those, EnumTypes.F
has not yet been initialized. Therefore, the reference to it is null
.From there, static initialization of the two enum classes finishes, but it doesn't matter for EnumGrammar.ZERO
- its values
field has already been set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With