2012-06-15 32 views
2

我有一個有趣的初始化問題。我有以下代碼:加載類時未初始化靜態變量

​​

現在,當我打電話ErrorLookupProvider.getInstance(),我打了一個NPE。 init()中的地圖未使用新的HashMap進行初始化。

如果我將map的聲明更改爲final,那麼我會看到它已初始化。或者,即使我刪除靜態並將其設置爲私有類變量private Map<.....>也可以。

我一直無法弄清楚爲什麼會發生這種情況。有人可以解釋這裏發生了什麼嗎?

+0

會,即使非長映射鍵編譯? –

+0

我的錯誤,我錯過了123L – Sudoer

回答

2

http://javapapers.com/core-java/explain-the-final-keyword-in-java/

引用被聲明爲final和未初始化叫做空白最終變量的變量。一個空白的final變量強制構造函數初始化它。

這就是爲什麼聲明爲final,當它被初始化

+0

它甚至是有效的調用私人靜態最終ErrorLookupProvider INSTANCE = new ErrorLookupProvider(); 類的初始化首先是靜態變量,靜態塊,成員變量和構造函數。但是,在這種情況下,調用構造函數來初始化靜態變量甚至是有效的嗎? – Sudoer

+0

是的,那很好。對你的代碼只是一個小小的評論,你可以用它作爲你的HashMap的聲明這個 private static Map > map = new HashMap <>(); – MaVRoSCy

+0

NO NO NO,當聲明爲final時,如果變量未由您初始化,構造函數將強制它初始化 – MaVRoSCy

2

新增:訂購事宜。在之前將您的靜態地圖的聲明放在INSTANCE的聲明中。 Java編譯器在訂購時有點愚蠢......

由於映射是靜態的,因此它在所有ErrorLookupProvider實例中共享。因此,在構造函數中使用它可能是一個錯誤。如果您創建多個ErrorLookupProviders,則會多次冗餘地添加到地圖中。相反,請在靜態初始化塊中初始化它。或者,如果它確實是要在ErrorLookupProvider的實例之間獨立,請不要將其設爲靜態。

5

切換映射和單例實例初始化的順序。

靜態初始化按其在源中遇到的順序發生。

請參閱JLS 12.4.2 Detailed Initialization Procedure步驟6(final部分)和9(「訂單」部分)。

(單例的實現,並在構造函數靜碴,單獨的問題。)

+0

哦!這是因爲靜力學的順序。如果我先把地圖放在地圖上,那我想也行。 這導致我問題 - 這甚至允許? private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider(); 通過排序,我通過調用構造函數初始化我的靜態變量。這意味着甚至在變量初始化之前調用構造函數。這個用法不正確嗎? Usualy中,init情況如下: 1.靜態成員 2.靜態塊 3.會員瓦爾 4.構造 現在,我想從1跳轉到4.如果這是不允許的? – Sudoer

+0

@Sudoer是的,這就是我們所說的 - 順序重要:)當然它是允許的 - 它的工作原理,不是嗎? –