【はじめてのJava】superによるメソッド呼び出し2【クラスの継承編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
クラスの継承編
クラスの継承編では、Javaを扱う上で重要な「クラスの継承」について扱っていきます。
前回はsuperを使ったメソッドの呼び出し方法をついて扱いました。
今回もsuperを利用したメソッドの呼び出しについて扱います。
目次
thisとsuper
Javaのプログラムを見ているとthisやsuperといったキーワードを見かけることがあります。
thisについてはこちらの記事の通り、そのインスタンス自身を表すキーワードです。
同様にsuperについてはこちらの記事の通り、親クラスで定義されている要素を示すキーワードです。
superとは
superとは 親クラス の要素を指し示すキーワードです。
メソッドの呼び出し時にはsuperを付けることで、 親クラスで定義されているメソッドを呼び出せます 。
superを使ったメソッドの呼び出し
super.メソッド名という呼び出し方をすると、親クラスで定義されているメソッドを呼び出すことができます。
この呼び出し方は、単純に親クラスで定義されているメソッドを呼び出すために使うこともありますが、主にオーバーライドと組み合わせて使います。
オーバーライドと組み合わせる
では、superを使ったメソッド呼び出しをオーバーライドとどのように組み合わせるのか見てみましょう。
オーバーライド(おさらい)
まずは改めてオーバーライドを思い出してみましょう。
オーバーライドとは、親クラスで定義したメソッドを子クラスで上書きすることと紹介しました。オーバーライドを使えば、親クラスで定義したメソッドと同名で異なる動作をするメソッドを、子クラス内で定義可能です。
例えば以前の記事ではPoliceCarクラスでaccell()メソッドをオーバーライドし、「通常時はspeedを10増加させ、追跡中はspeedを20増加させる」という動作にしていました。
その時のソースコードを基に、今回の説明に必要な部分だけを抜き出すと以下のソースコードになります。
Carクラス(親クラス)
class Car { double speed; void accell(){ this.speed += 10; } }
PoliceCarクラス(子クラス)
class PoliceCar extends Car{ boolean isChasing; //追跡中ならtrue、それ以外はfalse void accell(){ if(this.isChasing){ //追跡中の時 this.speed += 20; //speedを20増やす }else{ //追跡中ではないとき this.speed += 10; //speedを10増加させる★ } } }
このソースコードの問題点
このソースコードのままでも問題ないと言えば問題ありません。
そこで、もし★の動作がCarクラスのaccell()メソッドと同じ動作になってほしいという意図だった場合を考えてみましょう。
実はそのような意図だった場合、メンテナンス性に問題が生じます。
今のままではPoliceCarクラスのaccell()メソッドに直接処理内容を記述しているため、Carクラスのaccell()メソッドの動作を変更した場合、PoliceCarクラスのaccell()メソッドにはその内容が反映されません。
そこで、PoliceCarクラスのaccellメソッド内の該当箇所を super.accell()とします 。
ソースコードは以下の通りです。
PoliceCarクラス
class PoliceCar extends Car{ boolean isChasing; //追跡中ならtrue、それ以外はfalse void accell(){ if(this.isChasing){ //追跡中の時 this.speed += 20; //speedを20増やす }else{ //追跡中ではないとき //変更前 //this.speed += 10; //speedを10増加させる★ //変更後 super.accell(); //親クラスのaccell()メソッドをそのまま利用 } } }
このように記述することで、該当箇所ではCarクラスのaccell()メソッドが呼び出されることになります。
こうすることで、Carクラスのaccell()メソッドの動作が変更されても、PoliceCarクラスでsuper.accell()と呼び出している個所では変更が反映されるようになります。
おまけ
今回のPoliceCarは下記のソースの★2の箇所を見ると「追跡中」の場合はCarクラスのaccell()メソッドと関係なく動作するようになっています。
PoliceCarクラス
class PoliceCar extends Car{ boolean isChasing; //追跡中ならtrue、それ以外はfalse void accell(){ if(this.isChasing){ //追跡中の時 this.speed += 20; //speedを20増やす★2 }else{ //追跡中ではないとき //変更前 //this.speed += 10; //speedを10増加させる★ //変更後 super.accell(); //親クラスのaccell()メソッドをそのまま利用 } } }
★2の箇所を以下のように変えることで、追跡中の場合もCarクラスのaccell()メソッドの変更が反映されるようになります。
(ソースコードが長くなるため、おまけの紹介とします。)
PoliceCarクラス
class PoliceCar extends Car{ boolean isChasing; //追跡中ならtrue、それ以外はfalse void accell(){ if(this.isChasing){ //追跡中の時 //this.speed += 20; //speedを20増やす★2 //以下のように変更 for(int i = 1; i <= 2; i++){ super.accell(); } }else{ //追跡中ではないとき //変更前 //this.speed += 10; //speedを10増加させる★ //変更後 super.accell(); //親クラスのaccell()メソッドをそのまま利用 } } }
サンプルプログラム
今回作成したサンプルプログラムは以下の通りです。また、動作確認用のDrive.javaも記載しておきます。
なお、すべて同じディレクトリに保存して動作を確認してください。
Carクラス(親クラス)
class Car { double speed; void accell(){ this.speed += 10; } }
PoliceCarクラス(子クラス)
class PoliceCar extends Car{ boolean isChasing; //追跡中ならtrue、それ以外はfalse void accell(){ if(this.isChasing){ //追跡中の時 this.speed += 20; //speedを20増やす }else{ //追跡中ではないとき //変更前 //this.speed += 10; //speedを10増加させる★ //変更後 super.accell(); //親クラスのaccell()メソッドをそのまま利用 } } }
PoliceDriveクラス(動作確認用クラス)
public class PoliceDrive{ public static void main(String[] args){ PoliceCar panda = new PoliceCar(); panda.isChasing = false; //通常時 panda.accell(); System.out.println("panda.speed = " + panda.speed); //比較用に2台目をインスタンス化 PoliceCar panda2 = new PoliceCar(); panda2.isChasing = true; //追跡中 panda2.accell(); System.out.println("panda2.speed = " + panda2.speed); } }
まとめ
・オーバーライドを利用する場合にはsuper.メソッド名による親クラスのメソッド呼び出しをうまく使うことでソースコードのメンテナンス性が向上することがある
次回
次回はコンストラクタでのsuperの使い方について扱います。
はじめてのJavaシリーズの目次はこちら
クラスの継承編はこちら