我認爲我在我的一些代碼中發現了一個錯誤,儘管它在所有情況下似乎都沒有後退。我希望比我聰明的人可以明確地說「是的,這是一個錯誤」,更好的是,爲我的實施提出另一種替代方案。初始化引用彼此的靜態字段時出錯
我相信錯誤的來源是如何初始化兩個類的靜態字段;一個(在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如何描述這種相互參照初始化是如何完成的。
不幸的是,這個示例遠離我們的真實實現,我可能會花費相同的時間翻譯任何解決方案,但這將是值得的一些解釋。
不幸的是(WRT您的第三種類型的修復),設計的基本組成部分是'FooClass.ITS_FOO'場是一種特殊的'FooClass'。簡化我的例子擺脫了這個事實:(。但是,我仍然感到驚訝的構造函數可以在類初始化之前執行(儘管在這種情況下它聽起來有點神奇)。無論如何,我會想辦法擺脫其中一個依賴;這聽起來像是一個壞主意...... – 2012-03-14 18:31:34
@Rob:這一點從第12.4.2節的這一點開始:「如果C的Class對象表示當前線程正在對C進行初始化,那麼這必須是一個遞歸的初始化請求,釋放LC並正常完成。「 – 2012-03-14 18:32:28
啊!我之前並沒有完全遵循這個措辭,但現在我發現這個案子和它的「完整正常」是誤導性的......導致了「非常糟糕的主意」。謝謝! – 2012-03-14 18:50:52