2

初期化について興味深い質問があります。私は次のコードを持っています:

public class ErrorLookupProvider {  

private static final ErrorLookupProvider INSTANCE = new ErrorLookupProvider();

private  static Map<Long, List<String>> map = new HashMap<Long, List<String>>();

    private ErrorLookupProvider() {
        init();
    }

    private void init() {
        map.put(123L, ImmutableList.of("abc", "def"));
    }

    public static ErrorLookupProvider getInstance() {
        return INSTANCE;
    }
}

今、私が電話をするときErrorLookupProvider.getInstance()、私はNPEを打ちます。内部のマップinit()は新しいで初期化されていませんHashMap

の宣言をmapfinalに変更すると、初期化されていることがわかります。または、staticを削除してプライベートクラス変数にしたとしても、private Map<.....>それも機能します。

なぜこれが起こるのか理解できませんでした。誰かがここで何が起こっているのか説明できますか?

4

3 に答える 3

5

マップとシングルトンインスタンスの初期化の順序を切り替えます。

静的初期化は、ソースで検出された順序で発生します。

JLS 12.4.2詳細な初期化手順のステップ6(final部分)および9(「注文」部分)を参照してください。

(シングルトンの実装とctorでの静的な操作、別の問題。)

于 2012-06-15T23:22:28.390 に答える
2

http://javapapers.com/core-java/explain-the-final-keyword-in-java/からの引用

最終として宣言され、初期化されていない変数は、空白の最終変数と呼ばれます。空白のfinal変数は、コンストラクターにそれを初期化するように強制します。

そのため、ファイナルと宣言されると初期化されます

于 2012-06-15T23:12:12.967 に答える
2

追加:注文が重要です。静的マップの宣言をINSTANCEの宣言の前に置きます。Javaコンパイラは順序付けについて少し愚かです...

マップは静的であるため、のすべてのインスタンス間で共有されますErrorLookupProvider。したがって、コンストラクターでそれを操作するのはおそらく間違いです。複数のErrorLookupProviderを作成すると、マップに何度も冗長に追加されます。代わりに、静的初期化ブロックで初期化してください。または、のインスタンス間で実際に独立することを意図している場合はErrorLookupProvider、静的にしないでください。

于 2012-06-15T23:19:11.960 に答える