Javaでは、コンストラクタ(Constructor)の呼び出しが連鎖して実行される仕組みがあります。これを「コンストラクタチェーン」と呼びます。

結論から言えば、コンストラクタが別のコンストラクタを呼び出すっていうだけです。ですが、深堀すると例えば以下2パターンのコンストラクタチェーンに分けることができたり、それぞれの呼び出し方などに深みがありますので、このページではそこに特化して解説します。
- 親クラス → 子クラス のコンストラクタチェーン
- 同じクラス内 の
this(...)呼び出しによるチェーン
Java Silverなどの資格試験でも差が付きやすい分野の内容です。是非最後までご覧ください。
親クラスと子クラス:superによるコンストラクタチェーン
最も基本的なコンストラクタチェーンは、継承でつながったクラス階層におけるコンストラクタチェーンです。(参考 クラスの継承)子クラスのコンストラクタが呼ばれるときは、親クラスのコンストラクタが先に呼ばれるというルールによって繋がるコンストラクタの連鎖です。
class A {
A() {
System.out.println("A()");
}
}
class B extends A {
B() {
System.out.println("B()");
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
}
}
実行フロー
new B()でB()コンストラクタに入る。B()の先頭行に 暗黙的にsuper()が挿入されており、A()が先に呼ばれる。A()内の処理が終わってから、B()内の処理が行われる。- よって出力は以下の通りとなる。
A() B()
深堀:「暗黙的に挿入される」super
Javaでは、子クラスのコンストラクタの先頭に super() を明示的に書いていない場合、コンパイラが自動で super(); を補ってくれるという仕様があります。
✅ 例1:明示しない場合(暗黙に挿入される)
class A {
A() {
System.out.println("A()");
}
}
class B extends A {
B() {
System.out.println("B()");
}
}
この B() の中には super(); が書かれていませんが、実際には以下のように扱われます:
B() {
super(); // ← コンパイラが自動で挿入
System.out.println("B()");
}
// 結果として、new B() をすると出力は↓:
// A()
// B()
🚫 例2:親クラスに引数付きコンストラクタしかない場合
class A {
A(int x) {
System.out.println("A(int)");
}
}
class B extends A {
B() {
System.out.println("B()");
}
}
この場合はどうなるかというと…コンパイルエラーになります!
なぜなら、コンパイラは B() に対して勝手に super(); を補おうとするのですが、A クラスには引数なしの A() が存在しないからです。
| 状況 | コンパイラの動作 | 結果 |
|---|---|---|
super(...) が明示的に書かれている | そのまま使用 | OK |
super(...) を書いていない | 暗黙的に super(); を補う | OK(親に引数なしがあれば) |
親に引数ありコンストラクタしかないのに super() を省略 | 暗黙の super(); がエラー原因に | コンパイルエラー |
同じクラス内での this によるコンストラクタチェーン
同じクラス内での別コンストラクタを呼びたいときに使うキーワードが this(...) です。
class B {
B() {
this(100); // 自クラスのコンストラクタ B(int) を呼び出す
System.out.println("B()");
}
B(int x) {
System.out.println("B(int x) : " + x);
}
}
実行フロー
new B()でB()が呼ばれる。this(100);により、B(int x)が先に呼ばれる。B(int x)の処理が終わったらB()に戻って続きが実行される。(↓実行結果)
B(int x) : 100 B()
深堀:this(...) とは?(基本)
this(...) は、同じクラス内の別のコンストラクタを呼び出すためのキーワードです。
これを使うことで、コンストラクタの中から別のコンストラクタを呼び出し、処理を再利用できます。
class Person {
String name;
int age;
// 引数2つのコンストラクタ
Person(String name, int age) {
this.name = name;
this.age = age;
}
// 引数1つのコンストラクタ → this(...) で2つ引数の方を呼び出す
Person(String name) {
this(name, 18); // デフォルト年齢を指定
}
}
📌 this(...) の仕様と制約
| 特徴 | 説明 |
|---|---|
| コンストラクタの最初の行でしか使えない | this(...) は必ず1行目に書く必要があります。 |
| コンストラクタ間の再利用が目的 | 引数が違うだけで処理が共通な場合などに便利です。 |
| 1回だけ呼び出せる | 連続して this(this(...)) のようなことはできません。 |
super() と this() の優先順位
Javaのコンストラクタでは、コンストラクタの最初の行で this(...) か super(...) のいずれかのみを呼び出せるというルールがあります(どちらも書かない場合は super() が暗黙的に挿入される)。
this()とsuper()を同時に書くことはできない。- もし
this()を書いたら、そこに明示的に書かない限りsuper()はこのあと別の場所で呼ばれる(か、暗黙に入る)。
以下のコードを見てください。
class A {
A() {
this(2); // 同じクラス内の A(int) を呼ぶ
System.out.println("A()");
}
A(int a) {
System.out.println("A(int): " + a);
}
}
class B extends A {
B() {
this(4); // 同じクラス内の B(int) を呼ぶ
System.out.println("B()");
}
B(int b) {
// ここで実際には「super()」が暗黙的に呼ばれる
System.out.println("B(int): " + b);
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
}
}
new B()でB()コンストラクタへ。B()の先頭行this(4)がある →B(int b)を呼びにいく。B(int b)の先頭に暗黙のsuper()→A()を呼びにいく。A()の先頭にthis(2)→A(int a)を呼びにいく。A(int a)が実行 → 戻ってA()の残り → 戻ってB(int b)→ 戻ってB()
この段階での出力順を時系列で並べると
A(int): 2A()B(int): 4B()
つまり、
A(int): 2 A() B(int): 4 B()
という順に出力されます。つまり、thisが呼ばれたらsuperはそこでは呼ばれない(=thisが呼んだ先のコンストラクタで呼び出される)ということ。
super() と this() はどちらもコンストラクタチェーンを構成する重要な要素ですが、「最初の1行にしか書けない」という共通ルールのもと、それぞれが持つ役割と呼び出し順に違いがあります。this() を使えば、自クラス内の別のコンストラクタを経由して super() にたどり着く構造になるため、直感とは異なる実行順になることも。設計やデバッグ時には、「どこで親の初期化が走るか?」を正確に把握することが、思わぬバグを防ぐカギになります。
コンストラクタチェーンのまとめ
- 継承関係 では「子クラスのコンストラクタ → 親クラスのコンストラクタ」の順で呼ばれる。実際には、子クラスのコンストラクタの先頭で
super()(暗黙または明示)を呼び出すため。 - 同じクラス内 で複数のコンストラクタがある場合、
this(...)で別のコンストラクタへ処理が飛ぶ。その中でさらに親クラスへのsuper()が呼ばれる流れができる。 - ルール:「コンストラクタの最初の行で
this(...)orsuper(...)のどちらか1つだけ」が適用される。書かない場合は自動でsuper()が補われる。 - 書き方のコツ:一度
this(...)が挟まると、自分クラスの別のコンストラクタへ飛んだ上でsuper()が呼ばれるので、呼び出し順が直感とズレる可能性がある。あらかじめ意識しておこう。
◆ ひとことアドバイス
コンストラクタの処理順はバグの原因になりやすいポイントです。「コンストラクタを呼ぶと、どこからどこへ飛んで、どのタイミングで親クラスが初期化されるのか」を、一度紙に書いて整理してみると理解が深まります。もし、「あれ、なんでこのメッセージが先に出るんだろう?」と思ったら、コンストラクタチェーンを疑ってログ出力を確認するのがおすすめです。
