我认为我的一些代码中发现了一个错误,尽管在所有情况下它都没有出现问题。我希望比我更聪明的人可以明确地说“是的,这是一个错误”,更好的是,建议另一个替代我的实现。
我认为错误的来源是如何初始化两个类的静态字段;通过引用另一个字段来初始化一个(在FooClass
中),并通过创建类型为MyUtility
的对象来初始化一个(在Foo
中)。抱歉,听起来不对劲;解释从来都不是我的强项。
我花了大部分时间试图减少问题,并且有一些可以运行的东西似乎可以证明这个问题。
public class Tester {
static class FooClass {
static final FooClass ITS_FOO = MyUtility.MY_FOO;
}
static class MyUtility {
static final FooClass MY_FOO = new FooClass();
static FooClass create() {
return new FooClass();
}
}
public static void main(String[] args) {
System.out.println("utility's: " + MyUtility.create()); // Line "A"
System.out.println("class's: " + FooClass.ITS_FOO); // Line "B"
}
}
我意识到这个设计看起来很奇怪,但不会试图证明它的真实性(真正的代码也是“奇怪的”结构,但在具有不同可见性的单独类中等)。我肯定会感谢有关更好方法的建议。
问题的要点(至少在这个程序中)是当行B执行时FooClass.ITS_FOO
字段是null
。如果我切换A行和B行的顺序,则这两个字段都不是null
。
我见过像In what order do static initializer blocks in Java run?这样的问题,但是Java Language Spec和{{3}}似乎都没有描述这种相互参照初始化是如何完成的。
不幸的是,这个示例远离我们的实际实现,我可能会花费相同的时间来翻译任何解决方案,但是值得一些解释。
答案 0 :(得分:4)
是的,如果您先强制FooClass
初始化,那么会触发MyUtility
初始化。 MY_FOO
的初始化程序将继续,因为FooClass
已在此主题中初始化,因此MY_FOO
将为非空。
另一方面,如果您从ITS_FOO
构造函数(当前只是默认值)中观察FooClass
,那么您会看到它在那里为空...
此行为 在规范中有详细记录 - 您链接到的部分提供了所有详细信息 - 但基本上,非常糟糕的主意有两种类型静态初始化器相互引用。不要试图以微妙的方式解决它:摆脱依赖。我意识到这可能是一种痛苦,但实际上,不值得考虑任何其他修复。
执行修复的一种方法可能是使用静态初始化程序提取第三种类型,该静态初始化程序不依赖于任何其他类型,以及其他两种类型类型可以依赖。
当然,在静态初始化程序中少做一些也很有用:)