Java 枚举的枚举为空
我正在为我的大学课程Java 1.6开发一个LALG编译器。所以我上了一堂类型课和语法课 枚举类型Java 枚举的枚举为空,java,reference,enums,null,Java,Reference,Enums,Null,我正在为我的大学课程Java 1.6开发一个LALG编译器。所以我上了一堂类型课和语法课 枚举类型 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 fu
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;
}
}
枚举语法
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;
}
}
当我调用EnumTypes.E.getEnumTiposValue().getValues()
时,其中应该是EnumTypes.F
值为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()));
}
}
有解决办法吗
谢谢 从本质上讲,在类完全构造之前,也就是在构造函数完成之前,允许对对象的引用进入类之外总是一件非常危险的事情。枚举是单例的。这里有两个类,它们的构造函数以循环依赖关系接收彼此的实例。再加上类加载是延迟的,所以类将被加载,枚举实例将在运行时创建,最终结果取决于枚举初始化的顺序,这听起来很合理 我现在无法引用JLS中的对应点(我会查找),但我相信如果您允许对对象的引用从构造函数外部“离开类”(由于枚举是由JVM初始化的单例),JVM可以自由地执行一些奇怪的操作 编辑:JLS中的这些要点对于本案例非常重要:
- -
由于枚举值在内部被视为静态最终字段(请参见下面的16.5),如果您从另一个枚举的构造函数内部引用一个枚举,而该枚举的构造函数引用了第一个枚举,这两个对象中至少有一个尚未完全初始化,因此此时引用可能仍然为null在构造该对象的线程中读取该对象的最后一个字段,按照通常的before规则对构造函数中该字段的初始化进行排序。如果在构造函数中设置字段后进行读取,则会看到最终字段分配的值,否则会看到默认值。
- -
枚举常量的类体中任何构造的明确赋值/取消赋值状态受类的常规规则管辖
- -字段初始化规则
- -初始化发生时
EnumTypes.E.getEnumTiposValue()
,触发EnumTypes
的类加载EnumTypes
的静态初始化开始-其枚举常量将按照声明的顺序初始化EnumTypes.A
到EnumTypes.D
被初始化EnumTypes.I
开始初始化-其构造函数调用引用了EnumGrammar.THREE
,触发类加载EnumGrammar
EnumGrammar
的静态初始化开始-其枚举常量将按声明顺序初始化EnumGrammar.ZERO
已初始化-其构造函数调用引用了EnumTypes.A
、EnumTypes.B
、EnumTypes.F
和EnumTypes.D
。其中,EnumTypes.F
尚未初始化。因此,对它的引用是null
从那时起,两个enum类的静态初始化完成,但这对于EnumGrammar并不重要。零-它的
值
字段已经设置。对于解决方法,假设您有EnumA和EnumB,我将把EnumB的名称放在EnumA的构造函数中
当您必须从EnumA检索EnumB时,只需使用EnumB.valueOf(EnumA.this.EnumB)
例如,问题是EnumB
public enum Question {
RICH_ENOUGH(R.string.question_rich_enough, Arrays.asList(Answer.RICH_ENOUGH_YES, Answer.RICH_ENOUGH_NO)),
ARE_YOU_SURE(R.string.question_are_you_sure, Arrays.asList(Answer.ARE_YOU_SURE_YES, Answer.ARE_YOU_SURE_NO)),
FOUND_A_NEW_JOB(R.string.question_found_new_job, Arrays.asList(Answer.FOUND_A_NEW_JOB_YES, Answer.FOUND_A_NEW_JOB_NO)),
// ...
答案是EnumA
public enum Answer {
RICH_ENOUGH_YES(R.string.answer_yes, "ARE_YOU_SURE"),
RICH_ENOUGH_NO(R.string.answer_no, "THAT_SOMEBODY"),
ARE_YOU_SURE_YES(R.string.answer_yes, null),
ARE_YOU_SURE_NO(R.string.answer_no, "FOUND_A_NEW_JOB"),
FOUND_A_NEW_JOB_YES(R.string.answer_yes, "GO_FOR_NEW_JOB"),
// ...
private final int answerStringRes;
// Circular reference makes nulls
private final String nextQuestionName;
Answer(@StringRes int answerStringRes, String nexQuestionName) {
this.answerStringRes = answerStringRes;
this.nextQuestionName = nexQuestionName;
}
每当我需要从答案中得到下一个问题时
public Question getNextQuestion() {
if (nextQuestionName == null) {
return null;
}
return Question.valueOf(nextQuestionName);
}
这应该足够简单,可以作为一种变通方法
示例源代码:我昨晚刚刚编写的一个开源Android趣味应用程序-+1,复制如下:看起来像是一个循环依赖性谜题,与两个枚举类相互引用的常量的静态init有关。如果您懒散地加载某些内容或使用一些奇怪的类加载器。如果您使用Java 7多线程类加载器,可能会重复IIRC,它会变得更糟糕:。