はじめに
本章では、オーバーライドの特質から導き出される、ポリモーフィズムについて説明します。
目次
- 継承ツリー上のオーバーロード
- メソッドのオーバーライド
- 共変戻り値
- ポリモーフィズム
- ポリモーフィズムの利用
- 章のまとめ
目標
ポリモーフィズムについて理解すること。
継承ツリー上のオーバーロード
同じ継承ツリー上であれば、サブクラスはスーパークラスのメソッドをオーバーロードできます。

例題(継承ツリー上のオーバーロード)
実際に作成し、実行結果を確認してましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Member |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Friend |
| 継承 | Member |
package chapter9; |
実行するためのクラス(Execクラス)を作成します。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Exec |
package chapter9; |
コンパイル例:> javac chapter9¥Member.java
> javac chapter9¥Friend.java
> javac chapter9¥Exec.java
実行例:> java chapter9.Exec
名前:佐藤
年齢:22
上記は継承ツリー上のオーバーロードの例です。Memberクラスがスーパークラス、Friendクラスがサブクラスです。
Friendクラス内のset()メソッドが、オーバーロードにあたります。
サブクラスのオーバーロード規則
サブクラスのオーバーロードには次のような規則があります。
- 引数の構成(型、順序、数)を変えることでオーバーロードになる
- 戻り値型やアクセス修飾子は自由に変えることができる

※引数の構成(型、順序、数)が同じだとコンパイルエラーになるので注意してください。
オーバーライド
スーパークラスとサブクラス間で、メソッド名が同じでかつ引数構成も全く同じメソッドを定義した場合、それはオーバーライド(再定義)といいます。
オーバーライドは、スーパークラスで定義したメソッドを再度サブクラスで定義しなおしたい場合に、おこないます。

例題(オーバーライド)
先ほど作成しました、Memberクラス、Friendクラス、Execクラスを修正し、実行結果を確認してましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Member |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Friend |
| 継承 | Member |
package chapter9; |
実行するためのクラス(Execクラス)を作成します。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Exec |
package chapter9; |
コンパイル例:> javac chapter9¥Member.java
> javac chapter9¥Friend.java
> javac chapter9¥Exec.java
実行例:> java chapter9.Exec
Friendクラスです。
上記、スーパークラスであるMemberクラスでdisp()メソッドを定義しており、サブクラスであるFriendクラスでオーバーライドしています。サブクラスのオブジェクト内は以下のようになっており、disp()メソッドを実行するとオーバーライドで再定義したオブジェクトが実行されます。

尚、コンパイラーへ明示的に伝える命令のことをアノテーションといいます。アノテーションは@(アットマーク)をつけて指定します。今回、サブクラスであるFriendクラスのdisp()メソッドに「@Override」と記述しています。コンパイラーへこのメソッドはオーバーライドしていることを明示的に伝えています。
オーバーライドのルール
オーバーライドには以下のルールがあります。

引数の構成が全く同じでなければならない型や並び順、個数などは完全に同じでなければならない原則として
戻り値の型を変更しない
ただし、戻り値が参照型の場合、サブクラス型へ変えても良いアクセス修飾子は、より公開範囲の広いものにだけ変更して良い
[アクセス修飾子の公開範囲の広い例]private → デフォルト、protected、public
デフォルト → protected、public
protected → public
それでは実際に確認してみましょう。
先ほど作成しました、Memberクラスのみを再度修正し、実行結果を確認してください。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Member |
package chapter9; |
コンパイル例:> javac chapter9¥Member.java
> javac chapter9¥Friend.java
> javac chapter9¥Exec.java
実行例:> java chapter9.Exec
Friendクラスです。
オーバーライドの継承元メソッドを実行する方法
オーバーライドによって実行されるメソッドは、継承先で定義しなおしたメソッドです。
もし継承元のメソッドを実行したい場合には、superキーワードを利用すると、サブクラス内でのみ実行することができます。

先ほど作成しました、Friendクラスを再度修正し、実行結果を確認してましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Friend |
| 継承 | Member |
package chapter9; |
コンパイル例:> javac chapter9¥Member.java
> javac chapter9¥Friend.java
> javac chapter9¥Exec.java
実行例:> java chapter9.Exec
Memberクラスです。
Friendクラスです。
上記、サブクラスのdisp()メソッド内で、「super.disp();」と記載しており、スーパークラスのdisp()メソッドを実行しています。
共変戻り値
オーバーライドでは戻り値を変更することができませんでした。ただし、クラス型の参照を返すメソッドだけは、戻り値型をサブクラスの型に変更できます。このように、変更した戻り値型を共変戻り値といいます。

例題(共変戻り値)
先ほど作成した、MemberクラスとFriendクラスを戻り値とした、TryクラスとMyTryクラスを作成し、実行結果を確認してみましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Try |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | MyTry |
| 継承 | Try |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | TryExec |
package chapter9; |
コンパイル例:> javac chapter9¥Try.java
> javac chapter9¥MyTry.java
> javac chapter9¥TryExec.java
実行例:> java chapter9.TryExec
Memberクラスです。
Friendクラスです。
上記は共変戻り値の例です。スーパークラスであるTryクラスのget()メソッドの戻り値がMember型ですが、それをオーバーライドしたサブクラスである、MyTryクラスのget()メソッドの戻り値がMember型のサブクラスであるFriend型を指定しています。
共変戻り値により、クラスの拡張が容易になり、汎用的に利用できるメリットがあります。
ポリモーフィズム
ポリモーフィズムは、多様性、多態性などといわれ、カプセル化、継承に続くオブジェクト指向の三大要素の一つです。ポリモーフィズムは、オーバーライド + 参照型の自動型変換によって実現することができます。
スーパークラスへの代入とオーバーライド
以下、EmployeeクラスとSalesMemberクラスを新たに作成し、まずは実行結果を確認しましょう。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Employee |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | SalesMember |
| 継承 | Employee |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | EmployeeExec |
package chapter9; |
コンパイル例:> javac chapter9¥Employee.java
> javac chapter9¥SalesMember.java
> javac chapter9¥EmployeeExec.java
実行例:> java chapter9.EmployeeExec
-----SalesMemberクラス-----
営業部ID:1000
上記の場合、Employeeクラスがスーパークラス、SalesMemberクラスがサブクラスです。EmployeeExecクラスが実行するクラスです。
EmployeeExecクラスに定義されている
「Employee emp = new SalesMember(“山田”,123,1000);」に注目してください。
左辺では「new SalesMember(“山田”,123,1);」でSalesMemberクラスのインスタンス化を行っています。
右辺ではEmployeeクラス型の変数「emp」へ代入しています。つまり、サブクラスであるSalesMemberクラスのオブジェクトをスーパークラスの型であるEmployee型へ、自動型変換によって代入しています。
そして、Employeeクラス型の変数「emp」の「disp()」メソッドを実行しています。

出力結果を見るとわかるように、emp.disp(); を実行すると、SalesMemberクラスでオーバーライドしたメソッドである disp()メソッドが実行されています。
このように、emp変数の型には関係なく、代入された時のオブジェクトでオーバーライドしたメソッドが実行されていることがわかります。

これを ポリモーフィズムといいます。
ポリモーフィズムは、同じ型の変数でも、違う型のオブジェクトを代入することで、様々な機能に変身することができます。
ポリモーフィズムの利用
機能を変更する継承を使うと、スーパークラスで大まかな機能を作っておき、サブクラスで詳細を作りこませてシステムを完成させることができます。この方法では、サブクラスでのオーバーライドの違いによって、同じスーパークラスからいろいろなシステムを作成できます。
そのようなシステムを「アプリケーション」と呼ぶことにすると、同じスーパークラスから機能の違う、いくつものアプリケーションを作成することができます。
一方、スーパークラス型の変数に、いろいろなサブクラス型のオブジェクトを代入して実行するとポリモーフィズムが働くので、それぞれ違う機能を発揮します。したがって、アプリケーションのスーパークラス型の変数に、いろいろなアプリケーションを代入して実行すると、それぞれ独自のアプリケーションとして動くはずです。
以下は、色々な言語であいさつをする「他言語挨拶システム」です。
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Greeting |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | JapaneseGreeting |
| 継承 | Greeting |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | Talker |
package chapter9; |
| 項目 | 名前 |
|---|---|
| プロジェクト | alj_study |
| パッケージ | chapter9 |
| クラス名 | LangurageExec |
package chapter9; |
コンパイル例:> javac chapter9¥Greeting.java
> javac chapter9¥JapaneseGreeting.java
> javac chapter9¥Talker.java
> javac chapter9¥LangurageExec.java
実行例:> java chapter9.LangurageExec
Japanese
こんにちは
Greetingクラスは挨拶文を作るクラス(スーパークラス)です。language()メソッドとmessage()メソッドが定義されているのみで、単にnullを返すだけのメソッドです。このままでは何の役に立たないメソッドです。
その為、継承したら機能を変更しなくてはならないメソッドです。
JapaneseGreetingクラスは日本語の挨拶を行うクラスです(Greetingクラスのサブクラスです。)
次はTalkerクラスです。Talkerクラスではポリモーフィズムを利用しています。
Talkerクラスは挨拶を実行するクラスです。runメソッドだけがあります。runメソッドは、Greeting型の引数を受け取り、引数から言語と挨拶文を取り出して表示します。
最後のLangurageExecクラスは実行するクラスです。実行結果を見ると、日本語での挨拶ができていることがわかります。

余力がある人は、JapaneseGreetingクラス以外に、英語であいさつする「EnglishGreetingクラス」を作成し、以下のような実行結果になるようにしてみてください。
実行例:> java chapter9.LangurageExec
English
Hello
まとめ
以下の要点をしっかり理解してから次の章へ進んでください。
継承ツリー上のオーバーロード
同じ継承ツリーであれば、サブクラスはスーパークラスのメソッドをオーバーロードできるクラス内でのオーバーロードでは、引数構成を変えないとコンパイルエラーになる継承ツリー上のクラス間のオーバーロードでは、引数構成を変えないとオーバーライドになる
継承ツリー上のオーバーロードの規則
引数の構成(型、順序、数)を変えることでオーバーロードになる戻り値型やアクセス修飾子は自由に変えることができる引数の構成(型、順序、数)が同じだとコンパイルエラーになる
メソッドのオーバーライド
- オーバーライドとはスーパークラスで定義したメソッドを再度サブクラスで定義しなおすこと
- 継承先のメソッドで、メソッド名が同じでかつ引数構成も全く同じメソッドを定義し、内容を再度定義すると、継承先のメソッドが有効になり、継承元のメソッドは無効になる。
- サブクラスのオブジェクトをインスタンス化し、サブクラス型の変数へ代入し、オーバーライドしたメンバメソッドを実行すると、継承先で再定義したメソッドが実行される
オーバーライドの規則
- 引数の構成が全く同じでなければならない
- 戻り値は同じでなければならない
- アクセス修飾子はよりゆるいレベルにのみ変更できる
- 継承したメソッドだけをオーバーライドできる
- superキーワードを利用するとスーパークラスのメソッドを実行することができる
共変戻り値
- オーバーロードの戻り値は、原則同じでなければならないが、継承ツリー関係がある場合はサブクラスの型を戻り値に指定することも可能(共変戻り値)
- 共変戻り値を定義すると、クラスの拡張が容易になり、汎用的に利用できる
ポリモーフィズム
- サブクラスのオブジェクトをスーパークラス型の変数へ代入し、オーバーライド元のメソッドを実行するとオーバーライド先のメソッドが実行される(ポリモーフィズム)
- ポリモーフィズムは、オーバーライド + 参照型の自動型変換をおこなうと利用できる。
- ポリモーフィズムを利用すると様々な機能を実現することができる