次の2つのクラスがあります
public class classA {
classA() {
System.out.println("A");
}
}
class classB extends classA {
classB() {
System.out.println("B");
}
}
そして実行中
classA c = new classB();
または
classB c = new classB();
常に与える
A
B
なんでこんなことが起こっているの?一見すると、どちらのシナリオでも、classB
コンストラクターのみが呼び出され、出力は次のようになると想定します。
B
しかし、これは明らかに間違っています。
これがJavaの仕組みです。親クラスのコンストラクターは、子クラスのコンストラクターが呼び出される前に、Object
を介してクラス階層全体にわたって呼び出されます。
the docs からの引用:
super()
を使用すると、引数のないスーパークラスのコンストラクターが呼び出されます。super(parameter list)
を使用すると、一致するパラメーターリストを持つスーパークラスコンストラクターが呼び出されます。注:コンストラクタがスーパークラスコンストラクタを明示的に呼び出さない場合、Javaコンパイラーは、スーパークラスの引数なしのコンストラクターへの呼び出しを自動的に挿入します。スーパークラスに引数のないコンストラクタがない場合、コンパイル時エラーが発生します。
Object
にはそのようなコンストラクターがあるので、Object
が唯一のスーパークラスである場合、問題はありません。サブクラスコンストラクターが明示的または暗黙的にスーパークラスのコンストラクターを呼び出す場合、
Object
のコンストラクターに戻るまで、コンストラクターのチェーン全体が呼び出されると考えるかもしれません。実際、これは事実です。これはコンストラクターチェーニングと呼ばれ、クラス降下の長い行がある場合は、これに注意する必要があります。
スーパークラスコンストラクターは構築プロセス中に常に呼び出され、サブクラスコンストラクターが呼び出される前にスーパークラスの構築が完了していることが保証されています。これは、すべてではないにしてもほとんどのオブジェクト指向言語に当てはまります。デフォルトのコンストラクターを呼び出さない場合は、パラメーターを使用してスーパークラスコンストラクターを明示的に呼び出すことができます。それ以外の場合、そのような呼び出しはコンパイラーによって自動化されます。
構築されるオブジェクトの点で両方のステートメントに違いはないので、同じ出力が表示されます。
new
を使用して同じオブジェクトを構築するときに左側の異なる参照型を使用するだけでは、オブジェクトの作成とコンストラクタのチェーンに関する限り、違いはありません。
2つのステートメントの違いは、オブジェクトが作成された後です。