静的フィールド (値がコンパイル時定数式ではない) にアクセスすると、そのフィールドを宣言するクラスの初期化がトリガーされ、その間に静的初期化子が実行されます。ただし、初期化子間に循環依存関係がない場合、初期化はフィールドが読み取られるまでに完了したことが保証されるだけです。
たとえば、プログラムを実行すると
class Bar {
static final long bar;
static {
System.out.println("Assigning bar");
bar = Foo.foo;
}
}
class Foo extends Bar {
static final long foo;
static {
System.out.println("Assigning foo");
foo = 1;
}
}
public class Test {
public static void main(String[] args) {
new Foo();
System.out.println(Bar.bar);
}
}
次の出力が得られます。
Assigning bar
Assigning foo
0
1
の新しいインスタンスを作成するためFoo
、Foo.class
が初期化され、最初Bar.class
に のフィールドを読み取るスーパークラス が初期化されますFoo.class
が、Foo.class
既に初期化されています。Java 言語仕様では、セクション 12.4.2 のステップ 3で、このような再帰的な初期化がすぐに完了することを義務付けています。つまり、呼び出し元には、部分的に初期化された状態のクラスが表示されます。つまり、Foo.foo
は読み取られた時点で割り当てられていないため、デフォルト値の 0 が含まれています。その値が に割り当てられBar.bar
、 の初期化が完了しますBar.class
。次に、イニシャライザをFoo.class
実行して の初期化を再開し、イニシャライザFoo.foo
を 1 に設定します。
実際には、クラスの依存関係を確認し、イニシャライザ間に循環的な依存関係がないようにプログラムを構成することをお勧めします。