次のコードは、null
を1回出力します。
class MyClass {
private static MyClass myClass = new MyClass();
private static final Object obj = new Object();
public MyClass() {
System.out.println(obj);
}
public static void main(String[] args) {}
}
コンストラクタが実行される前に静的オブジェクトが初期化されないのはなぜですか?
更新
私はこの例のプログラムを注意せずにコピーしただけで、2つのオブジェクトフィールドについて話していると思いましたが、最初のフィールドはMyClassフィールドであることがわかりました。
スタティックはソースコードで指定された順序で初期化されるためです。
これをチェックしてください:
class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}
それは印刷されます:
null
null
myClassObject
null
[〜#〜]編集[〜#〜]
わかりやすくするために、これを引き出します。
それは明らかですか?
編集2
Varmanが指摘したように、初期化中はそれ自体への参照はnullになります。あなたがそれについて考えるならば、それは理にかなっています。
これを説明する別の方法を試してみましょう...
これは、クラスMyClass
を最初に参照したときにJVMが通過するシーケンスです。
static { ... }
ブロックが含まれます。myClass
静的変数をMyClass
の新しいインスタンスに初期化します。MyClass
がすでにロードされている(バイトコード)および初期化の処理中であることを認識するため、初期化をスキップします。obj
の値を出力します。これはまだnull
です(ヒープおよびコンストラクタで初期化された変数の一部ではないため)。obj
をObject
の新しいインスタンスに設定する次の静的初期化子を実行します。obj
はnull
ではなく、Object
インスタンスへの参照になります。Javaは、final
変数に値が一度割り当てられることを指定します。コードが参照するときに値が割り当てられることが保証されているわけではありません。コードは、割り当て後に参照します。
これはバグではありません。これは、独自の初期化中にクラスの使用を処理するための定義された方法です。そうでない場合、JVMは無限ループに入ります。手順#3.3を参照してください(JVMが初期化の処理中のクラスの初期化をスキップしない場合、それは単に初期化し続けるだけです-無限ループ)。
また、これはすべて、最初にクラスを参照する同じスレッドで発生することに注意してください。次に、JVMは、他のスレッドがこのクラスを使用できるようになる前に、初期化が完了することを保証します。
これは、Javaが宣言された順に静的セクションを実行するためです。あなたの場合、シーケンスは
#1が実行されるとき、objはまだ初期化されていないため、nullを出力します。以下を試してみてください、違いがわかります:
class MyClass {
private static final Object obj = new Object();
private static MyClass myClass = new MyClass();
public MyClass() {
System.out.println(obj); // will print null once
}
}
一般的に言って、このような構成をすべて一緒に回避することをお勧めします。シングルトンを作成しようとしている場合、そのコードフラグメントは次のようになります。
class MyClass {
private static final MyClass myClass = new MyClass();
private Object obj = new Object();
private MyClass() {
System.out.println(obj); // will print null once
}
}
これは、静的フィールドがそれらが定義したのと同じ順序で初期化されるためです。
ゆうたろう
最初の静的フィールドmyclassのイニシャルが完全に構築されていないので...私が得る結果は
null null testInitialize.MyObject@70f9f9d8 null