ポリモーフィズムの入口のコードトレース

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

この単元で学ぶこと

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

本文解説

型を二段階で読む Parent p=new Child()では、まずParentに呼びたいメソッドがあるかを調べます。次に、そのインスタンスメソッドをChildがオーバーライドしていればChildの実装を使います。コンパイル時の利用可否と実行時の実装選択を一つにまとめないことが重要です。

引数型と多態性 static int read(Parent p){return p.value();}へChildを渡すと、引数変数はParent型でも実体はChildです。read内のvalueは子のオーバーライドを呼びます。呼出し側から処理を共通化でき、子ごとに別名のreadを用意する必要がありません。

戻り値型と実体 Parent make(){return new Child();}から返る参照は、呼出し側ではParent型の式です。Parentにない子専用操作を直接使うことはできません。返された実体はChildのままなので、親で宣言した操作のオーバーライドは機能します。

オーバーロードとの違い pick(Parent)とpick(Child)がある場合、Parent p=new Child();pick(p)では引数式の宣言型Parentからpick(Parent)を選びます。選んだメソッド内でp.value()を呼ぶと、そこでは実体型によるオーバーライドが働きます。二つの選択段階を別々に追います。

兄弟型のキャスト Parentを継承したAとBがあっても、Aの実体はBではありません。Parent p=new A();B b=(B)p;は実行時にClassCastExceptionです。一方、直接A型の式を無関係な兄弟Bへキャストすると、クラス間の変換可能性がないためコンパイル時に拒否されます。

インタフェースへの型変換 Object x=new User()でUserがNamedを実装するなら、Named n=(Named)xは成功します。implements関係は継承でも引き継がれます。Userの子AdminもNamedとして扱えます。同じ名前のメソッドを持つだけでimplements関係が自動成立するわけではありません。

型検査と分岐 Parent[] a={new A(),new Parent(),null}を走査し、p instanceof Aのときだけ加算すれば、Aだけが数えられます。nullのinstanceofはfalseなので、この検査だけなら例外は発生しません。配列全体がnullの場合の走査とは別の条件です。

フィールドとstaticを混同しない 親子に同名フィールドやstaticメソッドがあっても、インスタンスメソッドと同じ動的選択にはなりません。Parent p=new Child()でp.nはParentのn、p.kind()がstaticならParent側のkindです。多態性の追跡では、対象の宣言がフィールド・static・通常のインスタンスメソッドのどれかを最初に確認します。

図解

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

重要ポイント

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

間違えやすい点

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

用語解説

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

関連教材

参考資料

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

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