ポリモーフィズムの入口を理解する

多態性は共通の親クラスやインタフェースの型を通じて、実体ごとに異なる処理を呼ぶ仕組みです。宣言型で使える操作を検査し、実体型でオーバーライド先を選び、必要な参照型キャストを安全に判断します。

この単元で学ぶこと

  • 共通型を通じた動的呼出しを追う
  • 拡大参照変換とキャストの成功条件を判定する
  • instanceofとnullを使った型検査を判断する

本文解説

共通の操作を呼ぶ abstract class Shape{abstract int area();}をSquareとTriangleが実装すると、Shape[]に両実体を入れてarea()を順に呼べます。呼出し側は具体クラスごとの名前で分岐せず、共通の契約を使います。これが多態性の基本です。

抽象型の変数 Shape s=new Square()は合法です。禁止されるのはnew Shape()という抽象クラスの直接生成であり、抽象型の変数宣言ではありません。インタフェース型も同様に、実装クラスの参照を保持できます。

宣言型で操作を検査 Shapeにareaだけがあれば、Squareだけのside()をs.side()で直接呼べません。実体がSquareでもコンパイル時にはShapeの契約を基準に検査します。必要なら契約に操作を設計するか、型を確認して明示的にキャストします。

拡大参照変換 Child c=new Child();Parent p=c;は同じ実体を親として扱います。コピーして別の親オブジェクトを作る操作ではないため、p==cはtrueです。共通型にしても実体の型と子のオーバーライドは保たれます。

親から子へのキャスト Parent p=new Child();Child c=(Child)p;は実体がChildなので成功します。Parent p=new Parent();Child c=(Child)p;はコンパイルできても実行時にClassCastExceptionです。キャストによってParent実体へ子のフィールドを付け足すわけではありません。

instanceofで検査 p instanceof Childはpが非nullでChildまたはその子として扱える実体ならtrueです。pがParentだけの実体ならfalseです。if(p instanceof Child){Child c=(Child)p;...}なら、このブロック内のキャストを実体に照らして行えます。Java 11なのでパターン変数構文は使いません。

nullの型操作 Parent p=null;Child c=(Child)p;は成功しcもnullです。p instanceof Childはfalseです。キャスト成功後にcのインスタンスメソッドを呼ぶとNullPointerExceptionなので、キャストが通ることと非nullであることは別です。

契約を実装する複数のクラス interface Named{String name();}に対してUserとTeamが実装すれば、Named nを介してそれぞれのnameを呼べます。同じ操作を持つことを明示的なimplementsで結びます。型変換はこの宣言上の関係と実体の両方に従います。

図解

共通型から実体別の処理へ
キャストで共通型を外す前に、その操作を共通契約で表せないかを考える。

重要ポイント

  • 宣言型は呼出せるメンバー、実体型はオーバーライドの実行先に関係する。
  • 子から親・実装クラスからインタフェースへの代入は可能。
  • 親から子へ戻すキャストは実体がその型である必要がある。
  • キャストは実体を作り替えず、nullのinstanceofはfalse。

間違えやすい点

  • キャストすればどんな親実体も子へ変わると思わない。
  • instanceofがクラス名の完全一致だけを調べると思わない。
  • interfaceやabstract型の変数を宣言できないと思わない。

用語解説

多態性
共通型の操作を実体に応じた実装で実行すること。
拡大参照変換
子から親等、より一般的な型として扱う変換。
キャスト
明示的に型を指定して式を扱う変換。参照変換には実行時検査がある。
instanceof
非nullの参照が指定型として扱える実体かを検査する演算子。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。