はじめに
本章では、オーバーライドの特質から導き出される、ポリモーフィズムについて説明します。
目次
- 継承ツリー上のオーバーロード
- メソッドのオーバーライド
- 共変戻り値
- ポリモーフィズム
- ポリモーフィズムの利用
- 章のまとめ
目標
ポリモーフィズムについて理解すること。
継承ツリー上のオーバーロード
同じ継承ツリー上
であれば、サブクラス
はスーパークラス
のメソッド
をオーバーロード
できます。
例題(継承ツリー上のオーバーロード)
実際に作成し、実行結果を確認してましょう。
項目 | 名前 |
---|---|
プロジェクト | 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キーワードを利用するとスーパークラスのメソッドを実行することができる
共変戻り値
- オーバーロードの戻り値は、原則同じでなければならないが、継承ツリー関係がある場合はサブクラスの型を戻り値に指定することも可能(共変戻り値)
- 共変戻り値を定義すると、クラスの拡張が容易になり、汎用的に利用できる
ポリモーフィズム
- サブクラスのオブジェクトをスーパークラス型の変数へ代入し、オーバーライド元のメソッドを実行するとオーバーライド先のメソッドが実行される(ポリモーフィズム)
- ポリモーフィズムは、オーバーライド + 参照型の自動型変換をおこなうと利用できる。
- ポリモーフィズムを利用すると様々な機能を実現することができる