JLS には静的初期化ブロックの実行順序に関する保証はありますか?
-
26-09-2019 - |
質問
次のような構造を使用することが信頼できるかどうか疑問です。
private static final Map<String, String> engMessages;
private static final Map<String, String> rusMessages;
static {
engMessages = new HashMap<String, String> () {{
put ("msgname", "value");
}};
rusMessages = new HashMap<String, String> () {{
put ("msgname", "значение");
}};
}
private static Map<String, String> msgSource;
static {
msgSource = engMessages;
}
public static String msg (String msgName) {
return msgSource.get (msgName);
}
もらえる可能性はありますか NullPointerException
なぜなら msgSource
初期化ブロックは初期化するブロックの前に実行されます。 engMessages
?
(なぜやらないのかについて msgSource
上位の init の最後に初期化が行われます。ブロック:単なる好みの問題です。記載されている構造が信頼できない場合はそうします)
解決
はい、静的初期化ブロックはテキストの順序で実行されることが保証されています。
JLSからは、 セクション12.4.1:
その目的は、クラスまたはインターフェイス型には、それを一貫した状態にする一連の初期化子があり、この状態が他のクラスによって観察される最初の状態であるということです。 静的イニシャライザとクラス変数イニシャライザはテキストの順序で実行されます。, であり、たとえこれらのクラス変数がスコープ内にあるとしても (§8.3.3)、使用後にその宣言がテキストで表示されるクラスで宣言されたクラス変数を参照することはできません。この制限は、最も循環的な初期化や不正な初期化をコンパイル時に検出するように設計されています。
そしてから 12.4.2:
次に、クラスのクラス変数初期化子と静的初期化子、またはインターフェイスのフィールド初期化子を実行します。 テキスト順に, 、あたかも単一のブロックであるかのように。
ただし、個人的には、すべての変数宣言を先頭に置き、次に単一の静的初期化ブロックを置きます。そのほうがずっと理解しやすいと思います。
所属していません StackOverflow