【Java入門(3)オブジェクト指向:活用編 #4】継承とコンストラクタ

 

みのる
こんにちは。笑顔で感謝!✨ みのるコーチです。
今回も、ご覧いただき、ありがとうございます。

今回は…

Java入門3 オブジェクト指向:活用編 #4
継承とコンストラクタ

というテーマでお送りします。

彩香
継承の考え方は、理解しました。
そして 今度はコンストラクタとの結びつきですね。

今回も、よろしくお願いします。

剛留
そういえば 前回は、コンストラクタを書きませんでしたね。
ちょっと 気になっていたんです。

今回も、全集中で頑張ります!

【1】 継承とコンストラクタ

あるクラスAがあります。

その クラスA を継承した クラスB を考えましょう。

ここでは、クラスAがスーパークラス
クラスBがサブクラスです。

利用する側は、まずクラスBをインスタンス化します。

この時に 領域が確保されて
内部的に クラスBのコンストラクタが呼び出されます。

❶ クラスBのコンストラクタ呼び出し。

です。

継承は、クラスBがクラスAのメンバを
引き継ぎますが、コンストラクタは継承しません。

ですので、クラスBのコンストラクタは
最初にクラスAのコンストラクタを呼び出す必要があります。

❷ クラスAのコンストラクタ呼び出し。

この事によって、クラスA部分の
初期化を行う事ができるのです。

❸ クラスA部分の初期化。

です。

そして、クラスBのコンストラクタは その後に
クラスBで追加した差分の初期化を行います。

❹ クラスB部分の初期化。

です。

ここでは…

サブクラスのコンストラクタは、必ず最初に
スーパークラスのコンストラクタを呼び出す必要がある。

…この事を まず押さえておきましょう。

この イメージで考えておくと
今回の部分は 理解が深まります…。

【2】 super()

スーパークラスのコンストラクタの
呼び出し方法を見ていきましょう。

先ほどのイメージでは
この部分になりますね。

スーパークラスのコンストラクタは…

このような形式で呼び出すこととなります。

super(実引数,…)

コンストラクタの最初で、必ず呼び出します。

もし、super(実引数,…) を記述しなかった場合には…

引数なしの super() が 暗黙的に付加されます。

このあたりも、先ほどのイメージと共に
押さえておきましょうね。

スーパークラスの コンストラクタ呼び出し
✅ 呼び出し形式
  super(実引数,…);

✅ コンストラクタの最初に、必ず呼び出す。

✅ super(実引数,…); を記述しなかった場合
  引数なしの super(); が 暗黙的に付加される。

彩香
スーパークラスから、コンストラクタは継承しないから
必ず最初に呼び出す必要があるんですね。

そうすれば
スーパークラスの初期化は必ず行われると…。

理解しました。

剛留
質問です。前回は、コンストラクタを書きませんでしたが。
この場合には、どうなるのでしょう。
みのる
剛留くん。良いポイントに注目ですね。

コンストラクタの勉強をした時に、デフォルトコンストラクタ
のお話をした事を 覚えていますか?

デフォルトコンストラクタとは…

クラスにコンストラクタの記述がない場合に
Javaで暗黙的に付加されます。

「引数なし」「中身が空(処理なし)」の
コンストラクタのことです。

デフォルトコンストラクタ
✅ クラスにコンストラクタの記述がない場合に
  Javaで暗黙的に付加される。

✅ 「引数なし」「中身が空(処理なし)」の
  コンストラクタ。

前回の場合には、スーパークラス・サブクラスともに…

このデフォルトコンストラクタが暗黙的に
付加されていたのです。

(スーパークラス側)
暗黙的に付加されたコンストラクタ() {
}

(サブクラス側)
暗黙的に付加されたコンストラクタ() {
}

そして、更に今回ご紹介している
引数なしの super() が暗黙的に付加される事になるので…

(スーパークラス側)
暗黙的に付加されたコンストラクタ() {
  super(); // 暗黙的に付加
}

(サブクラス側)
サブクラスのデフォルトコンストラクタ() {
  super(); // 暗黙的に付加
}

このような形のコンストラクタが
暗黙的に付加されます。

結果的に…

サブクラスのデフォルトコンストラクタ
が最初に呼び出されて…

その最初で、スーパークラスのデフォルトコンストラクタ
が呼び出されて…

その最初で、java.lang.Object の引数なしコンストラクタ
が呼び出される…

サブクラスのデフォルトコンストラクタ()
 ↓
スーパークラスのデフォルトコンストラクタ()
 ↓
java.lang.Object の引数なしコンストラクタ()

という流れになっていたのです。

したがって、最終的に
java.lang.Object の初期化が行われた後に…

スーパークラスとサブクラスのフィールドには
Javaの既定値が 設定された状態で…

インスタンス化が 完了している事となるのです。

剛留
話が、繋がってきました…。

ブラボー!です!

彩香
質問です。コンストラクタのオーバーロードのところで
this() を勉強しました。

この this() も、コンストラクタの先頭に書く必要が
ありましたが、両方とも書くことはできますか?

みのる
確かに、this() についても、コンストラクタの
先頭で記述する必要がありましたね。

このことについて、次のコーナーで見ていきましょう。

【3】 this() と super()

this() は、コンストラクタの中で…

同一クラスの 別コンストラクタを
呼び出す時に使います。

同一クラスの別コンストラクタ呼び出し
は、このように記述します

this(実引数1, …)

の形式です。

そして、この this(実引数1, …)が必要な場合…

コンストラクタの先頭で記述

する必要があります。

同一クラスの別コンストラクタ呼び出し
✅ 呼び出し形式
   this(実引数1, …)

✅ this(実引数1, …) が必要な場合
  コンストラクタの最初に記述する。

そして、先ほど質問のあった

「this() と super() は
 共にコンストラクタの先頭に記述しますが
 同時に指定できますか?」

という質問に関してですが。

これは、指定できません。

疑問
「this() と super() は
 共にコンストラクタの先頭に記述しますが
 同時に指定できますか?」

  ▼ ▼

指定できません。

this(実引数,…) か super(実引数,…) の
どちらかを指定します。

指定しなかった場合には

引数なしの super()

が暗黙的に付加されます。

イメージ的には、こんな感じです。

サブクラスのコンストラクタが呼び出された場合を
考えましょう。

同一クラスの別コンストラクタを呼び出す時には
this(引数,…) の形で呼び出します。

そして、この別コンストラクタの先頭で
super(引数,…) を呼び出すこととなりますので…。

この 別コンストラクタ のほうに
super(引数,…) の呼び出しを 任せている形になります。

ここで、スーパークラスの初期化は済んでいて…

その後に、サブクラスのメンバの 初期化を行います。

したがって、this(引数,…) の後には、スーパークラスの
コンストラクタを呼び出せない事となっています。

ということで、コンストラクタの先頭では
this() の呼び出しか、super() の呼び出しか…

どちらか 一方 を指定することになります。

彩香
そういうことなんですね。

ブラボー。

【まとめ】

【1】 継承とコンストラクタ
✅ サブクラスのコンストラクタは
  必ず最初に、スーパークラスの
  コンストラクタを呼び出す必要がある。
【2】 super()
✅ コンストラクタの1行目で、必ず
  スーパークラスのコンストラクタ
  呼び出し super(実引数,…) を行う。

✅ super(実引数,…) を記述しなかった
  場合には、引数なしの super() が
  暗黙的に付加される。

【3】 this() と super()
✅ コンストラクタの先頭では
  「this(実引数,…) の呼び出し」
  「super(実引数,…) の呼び出し」
  いずれかを指定する。