Java 循环枚举初始化 - 发生了什么&为什么会发生这种情况?
在我们的代码中,我们得到了一些关于枚举的奇怪的 NPE。当我搜索时,我(或多或少)发现了以下情况:
public class EnumTest {
public static void main(final String[] args){
System.out.println("------ START ----- ");
System.out.println("BeezleBubs FOO's rockSteady is: " + BeezleBub.FOO.rockSteady);
System.out.println("RockSteady BAR's beezleBub is: " + RockSteady.BAR.beezleBub);
System.out.println("------ END ----- ");
}
public enum RockSteady {
BAR(BeezleBub.FOO);
public final BeezleBub beezleBub;
private RockSteady(final BeezleBub beezleBub) {
this.beezleBub = beezleBub;
System.out.println("Constructing RockSteady, beezleBub = " + beezleBub);
}
}
public enum BeezleBub {
FOO(RockSteady.BAR);
public final RockSteady rockSteady;
private BeezleBub(final RockSteady rockSteady) {
this.rockSteady = rockSteady;
System.out.println("Constructing BeezleBub, rockSteady = " + rockSteady);
}
}
}
由于某种原因,结果很尴尬。运行时,此测试输出:
------ START -----
Constructing RockSteady, beezleBub = null
Constructing BeezleBub, rockSteady = BAR
BeezleBubs FOO's rockSteady is: BAR
RockSteady BAR's beezleBub is: null
------ END -----
另一件事是,当您切换调用枚举的 System.out.prinln() 语句时,枚举的初始化也会发生变化。结果是:
------ START -----
Constructing BeezleBub, rockSteady = null
Constructing RockSteady, beezleBub = FOO
RockSteady BAR's beezleBub is: FOO
BeezleBubs FOO's rockSteady is: null
------ END -----
有人对发生的事情有清楚的解释吗?它与状态和状态有关。订单,但我不能完全确定它......
Possible Duplicate:
Java Enums: Two enum types, each containing references to each other?
In our code we got some weird NPE's concerning Enums. When I searched, I found (more or less) the following case:
public class EnumTest {
public static void main(final String[] args){
System.out.println("------ START ----- ");
System.out.println("BeezleBubs FOO's rockSteady is: " + BeezleBub.FOO.rockSteady);
System.out.println("RockSteady BAR's beezleBub is: " + RockSteady.BAR.beezleBub);
System.out.println("------ END ----- ");
}
public enum RockSteady {
BAR(BeezleBub.FOO);
public final BeezleBub beezleBub;
private RockSteady(final BeezleBub beezleBub) {
this.beezleBub = beezleBub;
System.out.println("Constructing RockSteady, beezleBub = " + beezleBub);
}
}
public enum BeezleBub {
FOO(RockSteady.BAR);
public final RockSteady rockSteady;
private BeezleBub(final RockSteady rockSteady) {
this.rockSteady = rockSteady;
System.out.println("Constructing BeezleBub, rockSteady = " + rockSteady);
}
}
}
For some reason the results are awkward. When run, this test outputs:
------ START -----
Constructing RockSteady, beezleBub = null
Constructing BeezleBub, rockSteady = BAR
BeezleBubs FOO's rockSteady is: BAR
RockSteady BAR's beezleBub is: null
------ END -----
The other thing is that when you switch the System.out.prinln() statements calling the Enums, the initialization of the enums change as well. Resulting in:
------ START -----
Constructing BeezleBub, rockSteady = null
Constructing RockSteady, beezleBub = FOO
RockSteady BAR's beezleBub is: FOO
BeezleBubs FOO's rockSteady is: null
------ END -----
Anyone has a clear explanation of what is happening? It has something to do with state & order, but I can't quite put my finger on it...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在Java中,类是延迟加载和初始化的。这意味着,无论您尝试首先打印哪个类的属性,都会先加载并初始化。一般来说,如果您有类的相互递归初始化程序,那么您应该避免在所有构造函数完成之前检查它们的属性。
原因很简单,Java 没有可以执行的初始化步骤序列来确保所有可能用途的原子初始化。
顺便说一句,这与枚举无关,它可能发生在普通的旧 Java 类中。
In Java, classes are loaded and initialized lazy. That means, whichever class's attribute you try to print first is loaded and initialized first. In general, if you have mutually recursive initializer of classes, then you should avoid to inspect their attributes before all constructors are finished.
The reason for that is simply that there is no sequence of initialization steps Java could perform which would ensure atomic initialization for all possible uses.
Btw, this has nothing to do with enums it can happen with plain old Java classes.
循环依赖并不酷,我必须承认我还没有生成这样的代码。我可以猜测,实例枚举实例按需初始化,并且第一个实例 pocked 拉出最终值,该值仍然为空(最终意味着您不能重新分配值,而不是它已经被分配)。当您戳第二个枚举时,第一个枚举已经创建,并且一切都按预期工作
Cyclic dependencies are not cool, and I must admit I did not produced such code yet. I can guess, that instances enum instances initialized on demand, and first instance pocked pulls final value which is still null ( final means that you can not reassign value, not that it was already assigned ). When you poke second enum, first was already created and eveything works as expected
第一个 println 语句需要 BeezleBub.FOO.rockSteady 的值。这样 BeezleBub 枚举就被加载了。要初始化 BeezleBub FOO 实例,它需要加载 RockSteady 枚举。因此,RockSteady 被加载,并且 BAR 常量被初始化为 BeezleBub.FOO 的当前值,该值仍然为 null,因为它正在初始化自身。然后初始化的 BeezleBub.FOO 常量被赋予 RockSteady.BAR 的值,该值不为空。
这是一个有趣的问题,因为这是其中一个枚举应该可变才能正确初始化的情况之一。
The first println statement needs the value of BeezleBub.FOO.rockSteady. So the BeezleBub enum is loaded. To initialize the BeezleBub FOO instance, it needs to load the RockSteady enum. So RockSteady is loaded, and the BAR constant is initialized to the current value of BeezleBub.FOO, which is still null since it's in the process of initializing itself. Then the initialized BeezleBub.FOO constant is assigned the value of RockSteady.BAR, which is non null.
It's an interesting problem, because it's one of the cases where one of the enum should be mutable in order to be properly initialized.