簡潔な答え
クラスの初期化が開始k
されると、初期値は 0 になります。
静的ブロック (宣言内の代入より前にあるため) が実行され、k
2 が代入されます。
次に、宣言内の初期化子が実行され、k
1 が割り当てられます。
長い説明
あなたの例は少し単純なので、この例を使用しましょう。
class TestInitOrder {
static {
System.out.println(TestInitOrder.stat1);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
str = "something";
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
private static final int stat1 = 10;
static final String str2 = "sdfff";
static String str = "crap";
private static int stat2 = 19;
static final Second second = new Second();
static final int lazy;
static {
lazy = 20;
}
static {
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
public static void main(String args[]) {
}
}
class Second {
public Second() {
System.out.println(TestInitOrder.second);
}
}
Java Language Specificationによると、セクション 4.12.5から:
プログラム内のすべての変数は、その値が使用される前に値を持つ必要があります。
- 各クラス変数、インスタンス変数、または配列コンポーネントは、作成時にデフォルト値で初期化されます
(仕様の次の行は、すべてのタイプのデフォルト値を指定します。基本的には、 、 、 などの 0 の0
形式0.0d
ですnull
。false
)
そのため、(これらの理由のいずれかにより) クラスが初期化される前に、変数は初期値を保持します。
詳細な初期化手順によると(ここでは興味深い手順のみを引用し、私のものを強調しています):
6. [...] 次に、値がコンパイル時の定数式であるインターフェイスのfinal
クラス変数とフィールドを初期化します(§8.3.2.1、§9.3.1、§13.4.9、§15.28)。
[...]
9. 次に、クラスのクラス変数初期化子と静的初期化子、またはインターフェイスのフィールド初期化子を、単一のブロックであるかのようにテキスト順に実行します。
ステップ 6 を見てみましょう。4 つのクラスfinal
変数: stat1
、str2
、second
。lazy
10
は定数式であるため、 はで"sdfff"
あり、 は実行順序により、 と の初期値を観測することはできません。観察を行うために、最も早くできるのはステップ 9 です。str2
stat1
の場合はsecond
、右辺がコンパイル時の定数式ではないため、その初期値が表示されることを示しています。
割り当ては静的ブロックで行われ、ステップ 9 で発生するため、ケースlazy
は異なります。したがって、その初期値を観察することができます。(まあ、コンパイラは、lazy
一度だけ割り当てられていることを注意深くチェックします)。
コンパイル時の定数式による最終的なクラス変数の初期化の後、静的ブロックと残りの初期化子が実行されます。
例からわかるように、静的ブロックと初期化はテキストの順序に従って行われます (str
変数の使用で示されています)。最初にnull
、次にsomething
、次にcrap
.