
Java道|親クラスと子クラスのコンストラクタの関係
子クラスが完成する前に、まず親クラスの土台が作られる。
Javaのコンストラクタの順番を知ると、継承の動きがぐっと立体的に見えてきます。
Javaで継承を使うと、子クラスは親クラスのフィールドやメソッドを受け継げます。
ここで次に大切になるのが、子クラスのオブジェクトを作ったとき、コンストラクタはどの順番で動くのか という点です。
サブクラスのオブジェクトも、通常どおり new を使って作成します。
しかし内部では、サブクラスだけがいきなり作られるわけではありません。
Javaでは、サブクラスのオブジェクトを作るときに、
| 順番 | 動くもの | 役割 |
|---|---|---|
| 1 | スーパークラスのコンストラクタ | 親クラス側の基本情報を初期化する |
| 2 | サブクラスのコンストラクタ | 子クラス側の追加情報を初期化する |
という順番で処理が進みます。
鬼滅の刃風にたとえると、柱の隊士が登場するとき、いきなり柱としてだけ完成するわけではありません。
まず鬼殺隊士としての基本情報が整い、そのあとで柱としての担当区域や役割が加わります。
つまり、親の土台が先にできて、その上に子の個性が乗る。
これが、親クラスと子クラスのコンストラクタの基本的な関係です。
↓クリックすると拡大表示されます。

サブクラスのオブジェクトは new で作る
サブクラスのオブジェクト作成は、特別に難しいものではありません。
基本はこれまでと同じように、new を使います。
たとえば、DemonSlayer を継承した PillarSlayer がある場合、次のように書きます。
PillarSlayer slayer1 = new PillarSlayer();この1行で、PillarSlayer 型のオブジェクトが作成されます。
ただし、このとき作られる slayer1 は、PillarSlayer だけの機能を持つわけではありません。
DemonSlayer から受け継いだ機能も使えます。
鬼滅の刃風にたとえると、柱は柱としての役割を持っていますが、同時に鬼殺隊士でもあります。
そのため、鬼殺隊士としての名前や階級を持ち、さらに柱としての担当区域も持てるわけです。
継承したメソッドと追加したメソッドはどちらも使える
サブクラスのオブジェクトでは、親クラスから受け継いだメソッドと、子クラスで追加したメソッドの両方を呼び出せます。
今回の例では、PillarSlayer オブジェクトから次のメソッドを使えます。
| メソッド | 定義されている場所 | 役割 |
|---|---|---|
| setSlayer() | DemonSlayer | 名前と階級を設定する |
| show() | DemonSlayer | 隊士の状態を表示する |
| setArea() | PillarSlayer | 担当区域を設定する |
ここで大切なのは、PillarSlayer の中に setSlayer() や show() を書いていなくても使えることです。
これは、PillarSlayer が DemonSlayer を継承しているからです。
継承とは、親クラスの内容を子クラスに同じように書き直すことではありません。
親クラスの機能を受け継ぎ、必要な追加機能だけを子クラスに書く仕組みです。
クラスの継承を確認する
ファイル名:Sample1.java
class DemonSlayer
{
private String name;
private String rank;
public DemonSlayer()
{
name = "隊士未登録";
rank = "階級未設定";
System.out.println("鬼殺隊士クラスの隊士を作成しました。");
}
public void setSlayer(String n, String r)
{
name = n;
rank = r;
System.out.println("名前を" + name + "に、階級を" + rank + "にしました。");
}
public void show()
{
System.out.println("隊士の名前は" + name + "です。");
System.out.println("階級は" + rank + "です。");
}
}
class PillarSlayer extends DemonSlayer
{
private int area;
public PillarSlayer()
{
area = 0;
System.out.println("柱クラスの隊士を作成しました。");
}
public void setArea(int a)
{
area = a;
System.out.println("担当区域を" + area + "にしました。");
}
}
class Sample1
{
public static void main(String[] args)
{
PillarSlayer slayer1 = new PillarSlayer();
slayer1.setSlayer("水月", "水柱");
slayer1.setArea(7);
slayer1.show();
}
}Sample1.java の処理の流れ
まず、main メソッドでは次の行で PillarSlayer オブジェクトを作っています。
PillarSlayer slayer1 = new PillarSlayer();このとき、見た目は PillarSlayer のオブジェクトだけを作っているように見えます。
しかし、PillarSlayer は DemonSlayer を継承しているため、最初に DemonSlayer 側のコンストラクタが動きます。
処理の順番は次のようになります。
| 順番 | 処理 | 内容 |
|---|---|---|
| 1 | DemonSlayer() | name と rank を初期化する |
| 2 | PillarSlayer() | area を初期化する |
| 3 | setSlayer("水月", "水柱") | 名前と階級を設定する |
| 4 | setArea(7) | 担当区域を設定する |
| 5 | show() | 名前と階級を表示する |
鬼滅の刃風にたとえると、まず鬼殺隊士として登録され、そのあと柱として担当区域を持つ流れです。
実行結果の例
鬼殺隊士クラスの隊士を作成しました。
柱クラスの隊士を作成しました。
名前を水月に、階級を水柱にしました。
担当区域を7にしました。
隊士の名前は水月です。
階級は水柱です。最初に表示されているのは、DemonSlayer のコンストラクタのメッセージです。
鬼殺隊士クラスの隊士を作成しました。
次に、PillarSlayer のコンストラクタのメッセージが表示されます。
柱クラスの隊士を作成しました。この順番がとても重要です。
子クラスのオブジェクトを作っているのに、先に親クラスのコンストラクタが動いています。
これは、子クラスが親クラスの土台の上に成り立っているからです。
コンストラクタは継承されない
継承では、親クラスのフィールドやメソッドを子クラスが利用できます。
しかし、コンストラクタは継承されません。
ここは少し混ざりやすいので、表で整理します。
| 項目 | 継承されるか |
|---|---|
| フィールド | 継承の対象になる |
| メソッド | 継承の対象になる |
| コンストラクタ | 継承されない |
ただし、コンストラクタが継承されないからといって、親クラスのコンストラクタが無関係になるわけではありません。
サブクラスのオブジェクトを作るとき、親クラスのコンストラクタは必ず呼び出されます。
つまり、コンストラクタは子クラスに受け継がれるのではなく、子クラスの生成時に親クラス側の初期化として呼び出される、ということです。
何も書かないと super() が自動的に呼ばれる
PillarSlayer のコンストラクタを見てみましょう。
public PillarSlayer()
{
area = 0;
System.out.println("柱クラスの隊士を作成しました。");
}この中には super() が書かれていません。
しかし、Javaではサブクラスのコンストラクタの先頭に何も書かない場合、自動的に親クラスの引数なしコンストラクタが呼ばれます。
つまり、内部的には次のようなイメージです。
public PillarSlayer()
{
super();
area = 0;
System.out.println("柱クラスの隊士を作成しました。");
}この super() によって、DemonSlayer() が先に動きます。
| 書いたコード | Java内部のイメージ |
|---|---|
| super() を書いていない | 自動的に super() が呼ばれる |
| super(n, r) を書く | 指定した親コンストラクタを呼ぶ |
鬼滅の刃風にたとえると、柱として登録する前に、まず鬼殺隊士としての登録処理が自動的に呼ばれるようなものです。
図:new PillarSlayer() のコンストラクタ順序
↓クリックすると拡大表示されます。

この図が示していること
この図では、new PillarSlayer() を実行したときのコンストラクタの順番を表しています。
最初に DemonSlayer() が動きます。
ここで、鬼殺隊士としての基本情報である name と rank が初期化されます。
そのあとに PillarSlayer() が動きます。
ここで、柱としての追加情報である area が初期化されます。
このように、サブクラスのオブジェクトは、
| 順番 | 初期化されるもの |
|---|---|
| 1 | 親クラスの部分 |
| 2 | 子クラスの部分 |
という順番で完成します。
super() で親クラスのコンストラクタを指定する
親クラスにコンストラクタが複数ある場合、子クラス側からどの親コンストラクタを呼ぶか指定できます。
そのときに使うのが super() です。
たとえば、DemonSlayer に次の2つのコンストラクタがあるとします。
| コンストラクタ | 内容 |
|---|---|
| DemonSlayer() | 初期値で鬼殺隊士を作る |
| DemonSlayer(String n, String r) | 名前と階級を受け取って鬼殺隊士を作る |
PillarSlayer 側で super(n, r) と書くと、DemonSlayer(String n, String r) を呼び出せます。
これにより、子クラスのオブジェクト作成時に、親クラス側の名前と階級もまとめて初期化できます。
親クラスのコンストラクタを確認する
ファイル名:Sample2.java
class DemonSlayer
{
private String name;
private String rank;
public DemonSlayer()
{
name = "隊士未登録";
rank = "階級未設定";
System.out.println("鬼殺隊士クラスの隊士を作成しました。");
}
public DemonSlayer(String n, String r)
{
name = n;
rank = r;
System.out.println("名前が" + name + "で、階級が" + rank + "の鬼殺隊士を作成しました。");
}
public void setSlayer(String n, String r)
{
name = n;
rank = r;
System.out.println("名前を" + name + "に、階級を" + rank + "にしました。");
}
public void show()
{
System.out.println("隊士の名前は" + name + "です。");
System.out.println("階級は" + rank + "です。");
}
}
class PillarSlayer extends DemonSlayer
{
private int area;
public PillarSlayer()
{
area = 0;
System.out.println("柱クラスの隊士を作成しました。");
}
public PillarSlayer(String n, String r, int a)
{
super(n, r);
area = a;
System.out.println("担当区域が" + area + "の柱クラスの隊士を作成しました。");
}
public void setArea(int a)
{
area = a;
System.out.println("担当区域を" + area + "にしました。");
}
}
class Sample2
{
public static void main(String[] args)
{
PillarSlayer slayer1 = new PillarSlayer("水月", "水柱", 7);
slayer1.show();
}
}Sample2.java の処理の流れ
Sample2.java では、次の行で PillarSlayer オブジェクトを作っています。
PillarSlayer slayer1 = new PillarSlayer("水月", "水柱", 7);このとき、PillarSlayer の引数付きコンストラクタが呼ばれます。
public PillarSlayer(String n, String r, int a)
{
super(n, r);
area = a;
System.out.println("担当区域が" + area + "の柱クラスの隊士を作成しました。");
}最初に書かれているのが、super(n, r) です。
この super(n, r) は、親クラス DemonSlayer の引数付きコンストラクタを呼び出しています。
public DemonSlayer(String n, String r)
{
name = n;
rank = r;
System.out.println("名前が" + name + "で、階級が" + rank + "の鬼殺隊士を作成しました。");
}処理の順番を整理すると、次のようになります。
| 順番 | 処理 | 内容 |
|---|---|---|
| 1 | super(n, r) | 親クラス側で名前と階級を初期化する |
| 2 | area = a | 子クラス側で担当区域を初期化する |
| 3 | メッセージ表示 | 柱クラスの隊士として作成完了を表示する |
| 4 | show() | 親クラスのメソッドで名前と階級を表示する |
鬼滅の刃風にたとえると、水月という隊士が水柱として登録され、そのあと担当区域7を持つ柱として完成する流れです。
Sample2.java の実行結果の例
名前が水月で、階級が水柱の鬼殺隊士を作成しました。
担当区域が7の柱クラスの隊士を作成しました。
隊士の名前は水月です。
階級は水柱です。この結果を見ると、まず DemonSlayer 側のコンストラクタが動いています。
名前が水月で、階級が水柱の鬼殺隊士を作成しました。そのあと、PillarSlayer 側のコンストラクタが動いています。
担当区域が7の柱クラスの隊士を作成しました。ここから、super(n, r) によって親クラスの引数付きコンストラクタが呼び出され、そのあとで子クラスの追加処理が行われていることが分かります。
super() を使うと何が便利なのか
super() を使うと、親クラス側の初期化をオブジェクト作成時にまとめて行えます。
Sample1.java では、いったん引数なしで PillarSlayer を作ってから、あとで setSlayer() を使って名前と階級を設定しました。
PillarSlayer slayer1 = new PillarSlayer();
slayer1.setSlayer("水月", "水柱");一方、Sample2.java では、オブジェクトを作る時点で名前、階級、担当区域を渡しています。
PillarSlayer slayer1 = new PillarSlayer("水月", "水柱", 7);この違いを表にすると、次のようになります。
| 書き方 | 特徴 |
|---|---|
| new PillarSlayer() のあとで setSlayer() | 作成後に名前と階級を設定する |
| new PillarSlayer("水月", "水柱", 7) | 作成時に名前、階級、担当区域を設定する |
必須情報を最初から持たせたい場合は、引数付きコンストラクタと super() を使うと自然です。
super() はコンストラクタの先頭に書く
super() には重要なルールがあります。
それは、コンストラクタの先頭に書く必要があるということです。
正しい書き方は次の形です。
public PillarSlayer(String n, String r, int a)
{
super(n, r);
area = a;
}次のように、先に子クラス側の処理を書いてから super() を呼ぶことはできません。
public PillarSlayer(String n, String r, int a)
{
area = a;
super(n, r);
}これは、親クラスの初期化が終わる前に子クラス側の処理を始めることを防ぐためです。
鬼滅の刃風にたとえると、柱として担当区域を決める前に、まず鬼殺隊士としての基本登録を済ませる必要がある、ということです。
図:super() で親コンストラクタを呼ぶ流れ
↓クリックすると拡大表示されます。

この図が示していること
この図では、PillarSlayer の引数付きコンストラクタから super(n, r) を使って、DemonSlayer の引数付きコンストラクタを呼び出す流れを表しています。
まず、DemonSlayer(String n, String r) で name と rank を初期化します。
そのあと、PillarSlayer 側で area を初期化します。
つまり super() は、
| 役割 | 内容 |
|---|---|
| 親クラスのコンストラクタを呼ぶ | スーパークラス側の初期化を行う |
| 呼び出すコンストラクタを選ぶ | 引数に合うコンストラクタを指定する |
| 初期化の順番を守る | 親を先に、子をあとに初期化する |
という役割を持っています。
this() と super() の違い
コンストラクタの中では、this() という書き方も出てきます。
this() と super() は似ていますが、呼び出す相手が違います。
| 記述 | 呼び出すもの |
|---|---|
| this() | 同じクラスの別のコンストラクタ |
| super() | スーパークラスのコンストラクタ |
鬼滅の刃風にたとえると、this() は同じ PillarSlayer クラス内の別の登録手順を使うことです。
super() は、親である DemonSlayer クラスの登録手順を使うことです。
たとえるなら、次のようになります。
| 書き方 | 鬼滅の刃風のイメージ |
|---|---|
| this() | 柱クラス内の別ルートで登録する |
| super() | 鬼殺隊士としての基本登録を行う |
this() と super() は同じコンストラクタ内で両方は書けない
this() も super() も、コンストラクタの先頭に書く必要があります。
そのため、同じコンストラクタの中で次のように両方を書くことはできません。
public PillarSlayer(String n, String r, int a)
{
this();
super(n, r);
}どちらも先頭でなければならないため、同時に使えないのです。
Javaは、コンストラクタの最初にどの初期化ルートから始めるのかを1つに決めます。
| 書き方 | 可能か |
|---|---|
| 先頭に super() | 可能 |
| 先頭に this() | 可能 |
| this() のあとに super() | 不可能 |
| super() のあとに this() | 不可能 |
親クラスと子クラスのコンストラクタを鬼滅の刃風に整理する
DemonSlayer は、鬼殺隊士としての共通の土台です。
名前や階級のような、どの隊士にも必要な基本情報を持っています。
PillarSlayer は、DemonSlayer を受け継いだ子クラスです。
鬼殺隊士としての基本を持ちながら、柱としての担当区域 area を追加しています。
オブジェクト作成時には、次の順番で処理が進みます。
| 順番 | 鬼滅の刃風のイメージ | Javaの処理 |
|---|---|---|
| 1 | 鬼殺隊士として登録する | DemonSlayer のコンストラクタ |
| 2 | 柱としての担当区域を加える | PillarSlayer のコンストラクタ |
| 3 | 完成した隊士として使う | メソッド呼び出し |
親クラスの土台が先に整い、その上に子クラスの追加要素が乗る。
この順番を押さえると、継承とコンストラクタの関係がかなり分かりやすくなります。
押さえておきたいポイント
| ポイント | 内容 |
|---|---|
| サブクラスのオブジェクト作成 | new で通常どおり作成できる |
| 継承したメソッド | サブクラスのオブジェクトから呼び出せる |
| 追加したメソッド | サブクラス独自の機能として呼び出せる |
| コンストラクタの順序 | 先にスーパークラス、次にサブクラス |
| コンストラクタの継承 | コンストラクタ自体は継承されない |
| 自動的な super() | 何も書かない場合、親の引数なしコンストラクタが呼ばれる |
| 明示的な super() | 親クラスの特定のコンストラクタを呼べる |
| this() | 同じクラス内の別コンストラクタを呼ぶ |
| 注意点 | super() と this() はどちらもコンストラクタの先頭に書く |
継承は、親クラスの機能を受け継ぐだけでなく、オブジェクト作成時の初期化の順番にも深く関係しています。
親クラスで共通の土台を整え、子クラスで追加の特徴を加える。
この流れが見えると、サブクラスのオブジェクト作成や super() の意味が自然に理解できるようになります。
