さて、私はこのようなクラスを持っているとしましょう:
public class SignupServlet extends HttpServlet {
private static final Logger SERVLET_LOGGER=COMPANYLog.open(SignupServlet.class);
private static final ExceptionMessageHandler handler = new ExceptionMessageHandler();
private static final SignupServletObservableAgent signupObservableAgent =
new SignupServletObservableAgent(null, SERVLET_LOGGER);
}
SignupObservableAgentの前にインスタンス化されるSERVLET_LOGGERに依存できるように、クラスローダーを使用してこれらのフィールドを順番に初期化できますか?
はい、ソースに表示される順序で初期化されます。 The Java Language Specification、§12.4.2 ですべての厄介な詳細を読むことができます。ステップ9を参照してください。
...クラス変数の初期化子とクラスの静的初期化子、またはインターフェイスのフィールド初期化子のいずれかを、最終的なクラス変数と値がコンパイルされるインターフェイスのフィールドを除いて、単一のブロックであるかのようにテキスト順に実行します。時間定数が最初に初期化されます...
静的フィールドの初期化は並べ替えることができると思います。少なくともそれが私が理解している方法です JMM仕様
プログラム変数(オブジェクトインスタンスフィールド、クラス静的フィールド、および配列要素)へのアクセスが、プログラムで指定された順序とは異なる順序で実行されているように見える場合がいくつかあります。
サブクラスとスーパークラスがある場合。
実際には質問に答えていませんが、ここでもっと質問します-)。静的フィールドの初期化順序に関する興味深い例に出くわしました。次に例を示します。
public class Foo {
private static final Long result = method1();
private static String string = "something";
private static Long method1() {
if (string == null) {
throw new IllegalStateException("BOOM");
}
return 1L;
}
public static void main(String[] args) {
System.out.println("here");
}
}
これにより、IllegalStateExceptionが生成されます。ここでのシーケンスは、最初にmethod1()を呼び出し、「文字列」値の初期化をバイパスする「結果」フィールドを評価することであることを理解しています。 「文字列」は定数を意味しますが、テストを作成するときに「最終」修飾子を付けるのを忘れました。しかし、そのような場合はランタイムで処理する必要がありますか? 「if(string == null)」を呼び出すとき、JREは、「string」が初期化されていないことを確認して初期化するのに十分スマートである必要がありますか?