Java入門|11章のまとめ

継承を知ると、戦士の型はつながり、役割は広がり、コードはもっと強くなる。
11章は、オブジェクト指向の「親から子へ受け継ぐ力」を学ぶ章です。

11章では、Java のオブジェクト指向の中でも、とても重要な「継承」の考え方を学びました。
継承は、すでに作ってあるクラスを土台にして、新しいクラスを効率よく作るためのしくみです。まったくゼロから作り直すのではなく、親クラスの力を受け継ぎながら、必要な特徴だけを子クラスに追加していけるので、クラス設計がぐっとしやすくなります。

ドラゴンボールでたとえると、この章で学んだことはとても自然です。
たとえば、サイヤ人という共通の戦士の型があって、その型を受け継ぎながら、エリートサイヤ人や特別な任務を持つ戦士を作っていく感覚です。親の力をそのまま使えるところは使い、子の個性として必要な機能だけを足していく。この考え方が、11章全体を通して流れていました。

さらにこの章では、ただクラスを増やすだけでなく、

  • スーパークラスとサブクラスの関係
  • protected によるアクセス範囲
  • オーバーライドによる子クラスらしい振る舞い
  • スーパークラス型でまとめて扱う多態性
  • final による制御
  • Object クラスという共通の親
  • toString、equals、getClass といった基本メソッド

まで、一連の流れとして学んできました。

この章は、単に extends の書き方を覚える章ではありません。
既存のクラスをどう活かし、どう広げ、どこを守り、どう共通化するか を考える章です。ここが見えてくると、Java のオブジェクト指向が、ただの文法の集まりではなく、設計そのものに関わる考え方だとはっきりわかってきます。

継承は「親の力を受け継いで新しいクラスを作る」しくみ

11章の中心にあったのは、継承です。
継承では、スーパークラスをもとにしてサブクラスを作れます。サブクラスは、スーパークラスのメンバを受け継ぎながら、自分に必要な新しいフィールドやメソッドを追加できます。

ドラゴンボールで言えば、サイヤ人という共通の設計図があり、その上にエリートサイヤ人という新しい型を作る感覚です。

  • 親クラスには共通部分を書く
  • 子クラスには個別の特徴を書く

この役割分担ができるので、同じようなコードを何度も繰り返し書かなくてすみます。
だから継承は、効率よくクラスを増やしていくための強力なしくみなのです。

サブクラスはスーパークラスのメンバを受け継ぐ

継承では、サブクラスはスーパークラスのメンバを受け継ぎます。
これによって、親クラスですでに用意されている機能を、子クラスでもそのまま使えます。

ドラゴンボール風に考えるなら、サイヤ人クラスに

  • 名前
  • 戦闘力
  • 自己紹介
  • 基本の表示機能

があれば、エリートサイヤ人クラスでもそれらを受け継げます。
そのうえで、

  • 担当エリア
  • 特別任務
  • 独自の表示

などを追加できるわけです。

ここで大事なのは、受け継いだメンバをもう一度書き直さなくてよいことです。
親クラスの共通部分を活かしながら、子クラスでは追加したい部分に集中できます。これが、継承によるコード再利用の大きなメリットでした。

protected は親子関係の中で使いやすいアクセス指定

11章では、メンバへのアクセスについても学びました。
スーパークラスの private メンバには、サブクラスから直接アクセスできません。一方で、protected メンバならサブクラスからアクセスできます。

この違いは、継承の設計ではとても大切です。

ドラゴンボールでたとえるなら、親クラスが持つ情報の中には、

  • 親クラスの内部だけで管理したいもの
  • 子クラスにも見せて使わせたいもの

があります。

そのとき、

  • private は親クラスの中だけで守る情報
  • protected は子クラスにも渡してよい情報

という使い分けになります。

つまり protected は、カプセル化を保ちながらも、親子の関係では柔軟に使えるようにするための指定です。
継承を使う場面では、何を隠し、何を子クラスに見せるのかを考えることがとても大事だとわかりました。

オーバーライドは「親のメソッドを子クラスらしく作り直す」しくみ

11章では、オーバーライドも大きなテーマでした。
オーバーライドとは、スーパークラスと同じメソッド名・同じ引数の形式を持つメソッドをサブクラスで定義し、子クラス向けに作り直すことです。

ドラゴンボールで考えると、親クラスに show という共通の表示メソッドがあっても、子クラスではそれだけでは足りないことがあります。

たとえばサイヤ人クラスの show では

  • 名前
  • 戦闘力

だけを表示するとしても、エリートサイヤ人クラスでは

  • 名前
  • 戦闘力
  • 担当エリア

まで表示したいかもしれません。

そのとき、同じ show という名前のまま、子クラス用に中身を作り直します。
すると、子クラスのオブジェクトに対して show を呼び出したときは、親クラスではなく子クラス側の show が使われます。

これは、継承が単なる受け継ぎで終わらず、子クラスらしさを表現するための仕組み でもあることを示しています。

スーパークラス型でまとめて扱えることが多態性につながる

11章では、サブクラスのオブジェクトをスーパークラス型の変数で扱えることも学びました。
これは、サブクラスのオブジェクトが、スーパークラスの一種でもあるからです。

ドラゴンボールで言えば、エリートサイヤ人は特別な戦士ですが、まずサイヤ人の一種でもあります。だから、サイヤ人型の変数でエリートサイヤ人を扱えます。

ここで面白いのは、見た目の型がスーパークラスでも、実際に入っているオブジェクトがサブクラスなら、オーバーライドされたメソッドはサブクラス側が動くことです。
つまり、同じ show という呼び出しでも、

  • 通常のサイヤ人なら通常のサイヤ人の show
  • エリートサイヤ人ならエリートサイヤ人の show

が働きます。

これが多態性、つまりポリモーフィズムの重要な感覚でした。
同じ命令でも、実際のオブジェクトに応じて違う振る舞いが起きる。この仕組みのおかげで、いろいろなオブジェクトをまとめて扱いやすくなります。

オーバーライドとオーバーロードは似ているが別物

11章では、オーバーライドとオーバーロードの違いも整理しました。
名前は似ていますが、考え方はかなり違います。

用語意味
オーバーロード同じメソッド名で、引数の形式が異なるメソッドを複数定義する
オーバーライドサブクラスで、親クラスと同じメソッド名・同じ引数の形式のメソッドを定義する

ドラゴンボールで言えば、

  • オーバーロードは、同じ技名でも使い方違いのバリエーションを用意すること
  • オーバーライドは、親から受け継いだ技を子が自分流に磨き直すこと

です。

ここを区別できるようになると、メソッドまわりの整理がかなりしやすくなります。

final は「それ以上変更させない」ための修飾子

11章では、継承やオーバーライドが便利である一方で、すべてを自由に変えさせればよいわけではないことも学びました。
そこで登場したのが final です。

final は付ける場所によって意味が変わります。

final を付ける場所意味
メソッドオーバーライドできない
クラス継承できない
フィールド値を変更できない

ドラゴンボール風に言えば、

  • この技の型は変えるな
  • この戦士の型はこれ以上派生させるな
  • この数値は世界の決まりだから変えるな

という意味になります。

つまり final は、自由に広げるだけではなく、ここは固定する と決めるための大切な修飾子でした。
設計では、どこを拡張可能にし、どこを固定するのかを考えることが重要だと見えてきます。

Java のクラスは最終的に Object クラスにつながる

11章の後半では、Object クラスのしくみも学びました。
Java では、スーパークラスを指定しないクラスは、自動的に Object クラスのサブクラスになります。
そのため、Java のクラスはすべて最終的に Object クラスにつながっています。

これはとても大きな考え方です。

ドラゴンボールでたとえるなら、どんな戦士クラスも、もっと上までたどっていけば、全員が共通の最も基本的な戦士の型につながっている、ということです。

だからこそ、すべてのクラスは Object クラスのメンバを受け継いでいます。
11章では特に、次の 3 つのメソッドが重要でした。

メソッド役割
toString()オブジェクトを表す文字列を返す
equals()オブジェクトが同じかどうかを調べる
getClass()オブジェクトのクラス情報を返す

Object クラスを知ると、継承はただの個別ルールではなく、Java 全体を支える共通の土台の上に成り立っていることがわかります。

toString() はオブジェクトの「名乗り方」を決める

toString() は、オブジェクトを文字列で表すメソッドでした。
オブジェクトをそのまま System.out.println に渡したとき、この toString() の戻り値が表示に使われます。

Object クラス由来のままだと、機械的な表示になりがちです。
そこで、自分のクラスで toString() をオーバーライドすると、よりわかりやすい文字列を返せるようになります。

ドラゴンボール風に言えば、戦士が

  • 名前
  • 戦闘力
  • 必要な追加情報

をわかりやすく自己紹介するようなものです。

オブジェクトをよく表示する場面では、toString() をオーバーライドしておくと、とても便利だということがわかりました。

equals() は「同じオブジェクトか」を調べる基本メソッド

equals() は、2つの変数が同じオブジェクトを指しているかどうかを調べるメソッドでした。
Object クラスの基本の equals() では、同じ実体を指している場合に true、別のオブジェクトなら false を返します。

ドラゴンボールで考えるなら、

  • 同じ戦士本人を2つの札で見ているなら true
  • 似ていても別々に作られた戦士なら false

という感覚です。

さらに、String クラスでは equals() がオーバーライドされていて、オブジェクトそのものではなく、文字列の内容が同じかどうかを見るように作り直されていることも学びました。

ここから、同じ equals() でも、クラスによって「同じ」の意味を変えられるという、オブジェクト指向らしい発想が見えてきます。

getClass() はオブジェクトの正体を調べる

getClass() は、オブジェクトが属しているクラスの情報を返すメソッドでした。
戻り値は Class クラスのオブジェクトで、そこにクラス情報が入っています。

スーパークラス型の配列で複数のオブジェクトをまとめて扱っているときでも、getClass() を使えば、そのオブジェクトが本当はどのクラスのものなのかを調べられます。

ドラゴンボールで言えば、見た目は同じサイヤ人型の配列に並んでいても、

  • 通常のサイヤ人なのか
  • エリートサイヤ人なのか

を確かめられる、ということです。

多態性では、見た目の型と実体のクラスがずれることがあります。
getClass() は、その正体を知るための基本メソッドとして役立つことがわかりました。

図で11章全体の流れを整理する

上側では、Objectクラス を頂点にして、Saiyanクラス、さらにその下に EliteSaiyanクラス がつながっている様子を見ます。
ここから、Java のクラスが継承でつながる階層構造を持っていることがわかります。

中央では、protected が親子関係の中で使いやすいアクセス指定であることと、show() のオーバーライドによって子クラスらしい振る舞いが実現できることを表しています。

下側の warriors[] の部分では、スーパークラス型でまとめて扱っていても、実体に応じて適切な show() が動くこと、つまり多態性を表しています。

右側の枠では、Object クラスから受け継ぐ基本メソッド toString()、equals()、getClass() をまとめています。
そして右上の final は、「自由に広げられるだけではなく、必要に応じて固定もできる」ことを表しています。

11章でいちばん大事な感覚

最後に、11章をひとつの感覚にまとめるとこうなります。

11章で学んだのは、親クラスを土台にして、新しいクラスを作り、その関係の中で役割を分けていく考え方 です。
そしてその中で、

  • 共通部分は親にまとめる
  • 個性は子に追加する
  • 必要ならオーバーライドで作り直す
  • まとめて扱うと多態性が生きる
  • 固定したいものは final で守る
  • すべてのクラスは Object クラスにつながる

という流れがありました。

ドラゴンボールで言えば、

  • 共通の戦士の型がある
  • そこから個性ある戦士クラスが生まれる
  • でも全員には共通の基本ルールもある
  • 同じ命令でも、戦士ごとに違う動きができる

という世界です。

この感覚がつかめると、継承は単なる文法ではなく、クラス設計そのものを考えるための強力な考え方だとわかります。
11章は、その土台をしっかり作る章だったと言えます。