誰でも次のプログラムの出力を説明できますか?コンストラクタはインスタンス変数の前に初期化されると思いました。そのため、出力が「XZYY」になると予想していました。
class X {
Y b = new Y();
X() {
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
初期化の正しい順序は次のとおりです。
セクション= Java Virtual Machine Specification の2.17.5-6を参照してください。
クラスファイルの逆コンパイルバージョンを見ると
_class X {
Y b;
X() {
b = new Y();
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y;
Z() {
y = new Y();
System.out.print("Z");
}
public static void main(String args[]) {
new Z();
}
}
_
インスタンス変数y
がコンストラクター内で移動されていることがわかります。そのため、実行シーケンスは次のようになります。
Z
のコンストラクターを呼び出しますX
のデフォルトコンストラクターをトリガーしますX
コンストラクターの最初の行new Y()
が呼び出されます。new Y()
の最初の行を呼び出しますY
すべてのインスタンス変数は、コンストラクターステートメントを使用して初期化されます。
コンストラクタを呼び出すと、インスタンス変数初期化子はコンストラクタの本体の前で実行されます。以下のプログラムの出力はどうだと思いますか?
public class Tester {
private Tester internalInstance = new Tester();
public Tester() throws Exception {
throw new Exception("Boom");
}
public static void main(String[] args) {
try {
Tester b = new Tester();
System.out.println("Eye-Opener!");
} catch (Exception ex) {
System.out.println("Exception catched");
}
}
}
Mainメソッドは、例外をスローするTesterコンストラクターを呼び出します。 catch節がこの例外をキャッチし、Exception catchedを出力すると予想される場合があります。しかし、実行しようとすると、そのようなことは何も行わず、StackOverflowError
がスローされることがわかりました。
静的に関する誤解を明確にするために、次の小さなコードを参照します。
public class Foo {
{ System.out.println("Instance Block 1"); }
static { System.out.println("Static Block 1"); }
public static final Foo FOO = new Foo();
{ System.out.println("Instance Block 2"); }
static { System.out.println("Static Block 2 (Weird!!)"); }
public Foo() { System.out.println("Constructor"); }
static public void main(String p[]) {
System.out.println("In Main");
new Foo();
}
}
驚いたことに、出力は次のとおりです。
Static Block 1
Instance Block 1
Instance Block 2
Constructor
Static Block 2 (Weird!!)
In Main
Instance Block 1
Instance Block 2
Constructor
after2つのインスタンスstatic {}
と呼ばれる{}
があることに注意してください。これは、コンストラクターが中間で呼び出され、コンストラクターが最初に呼び出されたときに実行順序を挿入するためです。
この答えに取り組んでいたときにこれを発見しました- https://stackoverflow.com/a/30837385/7441 。
基本的にこれが起こるのを観察します:
オブジェクトが初めて初期化されるとき、発生順序に基づいて混在する静的およびインスタンスの両方の初期化のために現在のオブジェクトを初期化します
次のすべての初期化では、静的な初期化がすでに行われているため、インスタンスの初期化は発生順にのみ実行してください。
継承の組み合わせ、およびsuperへの明示的呼び出しと暗黙的呼び出しの両方がどのようにこれに影響するかを調査する必要があり、結果を更新します。静的な初期化で問題が発生したことを除けば、提供された他の回答と似ている可能性があります。