2019/02/06
この記事は前回の続きになります。おさらいすると長くなるので、もしオーバーライドって何?を読んでいない人は先に読むようにして下さい。
前回、子クラスのインスタンスは親クラスのインスタンスを内包しているということを説明しました。この考えは継承の仕組みを理解する上で非常に重要なので覚えておいて下さい。
sponsored link
親インスタンスのフィールドにアクセスするsuper
superは、子インスタンスから内包する親インスタンスのメンバにアクセスしたい時に使います。
EconomyCarクラス
実際にsuperを使って、親インスタンスが持つnenpiというパラメータ(フィールド)にアクセスすることで、低燃費を実現できるEconomyCarクラスを書いてみましょう。
親であるCarクラスが以下のようになっているとしましょう。
Car.java
class Car{ int gas = 60; //ガソリン int nenpi = 10; //燃費 // gasを消費して走る public void drive(int gas){ this.gas -= gas; System.out.println(gas * this.nenpi + "km走りました"); } // 以下省略 }
Carクラスが持つパラメータはガソリン残量と燃費です。
driveメソッドによって走る距離は、引数に渡したガソリン使用料 × nenpiパラメータによって決まります。
このCarクラスを継承したEconomyCarクラスは以下のようにしましょう。
EconomyCar.java
class EconomyCar extends Car {
EconomyCar(){
super.nenpi = 20;
}
}
随分、スッキリしています。書いてあるのはコンストラクタのみです。
コンストラクタ内で、superを使ってEconomyCarインスタンスが内包している親インスタンスのnenpiフィールドを書き換えています。
このコンストラクタを書いておけば、EconomyCarクラスを普通にインスタンス化するだけで、内包するCarインスタンスのnenpiが20になったEconomyCarインスタンスを作ることができます。
そしてEconomyCarインスタンスのdriveメソッドを呼べば、Carインスタンスが持つdriveメソッドを経由してCarインスタンスのnenpiにアクセスすることが可能となり、リッター20kmの低燃費が実現します。
継承先(子クラス)のインスタンスでパラメータを管理するのではなく、パラメータに関しては全て親クラスのフィールドを使ういうと割り切った設計です。
SuperEconomyCarクラス
同じように、Carクラスを継承して、リッター30kmという超低燃費を実現したSuperEconomyCarクラスを書いてみましょう。
SuperEconomyCar.java
class SuperEconomyCar extends Car {
SuperEconomyCar(){
super.nenpi = 30;
}
}
これだけです。
先ほどと同じように、コンストラクタ内で親インスタンスのnenpiフィールドを書き換えています。今度はリッター30kmです。
こんな風に、内包している親インスタンスのフィールドをパラメータとして使えば、driveメソッドを子クラスでオーバーライドせずとも、燃費を操作することができます。
しかしこのやり方の場合、親クラスのデフォルトのnenpiである10という値は消えてしまうことになるので、その点はクラス設計として問題ないものか?注意が必要です。
今回は、継承の仕組みにスポットを当てるために、あえてカプセル化については言及していないので設計的には決して褒められたものじゃないのでご注意を。(^^;)
親インスタンスのメソッドにアクセスするsuper
もちろんsuperを使ってアクセス出来るのはフィールドだけではありません。
親インスタンスが持つメソッドにアクセスする際もsuperを使います。
ちょっといい例が思い浮かばなくて申し訳ないのですが、無理やり使ってみます。
今Googleが自動運転する車を開発していますが、それとよく似たので、自動で燃料を補給する車を作ってみます。言っときますが無理やりです。(笑)
この自動燃料補給車は、オートドライブ機能がついています。オートドライブ機能を使用して走ると、使った分だけ自動的に燃料を補給してくれるようになっています。どうやって補給するとかは突っ込まないようにしましょう。
AutoCar.java
class AutoCar extends Car { public void autoDrive(int gas){ super.drive(gas); super.putGas(gas); } }
↑このようにautoDriveメソッド内で、親インスタンスが持つdriveメソッドとputGasメソッドを呼んでいます。
autoDriveメソッドの引数に渡された値を、driveメソッドとputGasメソッドの引数にそのまま渡しているので、走った分だけガソリンを補給することになりますね。
このAutoCarクラスをインスタンス化して走らせてみましょう。CarTestクラスで走らせます。比較の為にCarクラスも走らせています。
CarTest.java
public class CarTest {
public static void main(String[] args) {
Car car = new Car();
car.drive(20);
car.drive(30);
car.putGas(40);
car.checkGas();
System.out.println("");
AutoCar aCar = new AutoCar();
aCar.drive(20);
aCar.autoDrive(30);
aCar.putGas(40);
aCar.checkGas();
}
}
CarTestクラスの実行結果がこちらです。↓
例はやや無理やりですが、親インスタンスが持つメソッドをsuperを使って呼んでいるのが分かりますでしょうか?
このように、superを使えば子クラスから親クラスのメンバ(フィールド・メソッド)を操作することが出来ます。
継承を使ってオブジェクトの特徴を設計する為には、どういうパラメータを用意して、そのパラメータを操作するメソッドをどのように定義するのか?が非常に重要になってきます。
親クラスのメソッドを書き替えてしまうオーバーライドと、親クラスのメンバにアクセスするsuperを上手く使って、扱いやすい継承関係、効率のいいクラス設計を実現しましょう。
今だけ→転職できなければ全額返金の「エンジニア転職保証コース」
絶対エンジニアになる!→テックエキスパート
フリーランスエンジニアの収入例を見てみる→レバテックフリーランス
コメント
ご丁寧にコメントしていただいてありがとうございます。
苦労して書いた甲斐がありました。(^^)
by Nobuo@管理人 2016/06/11 08:58
一番簡単なjava入門勉強させていただきました。
感謝します。
by アプリが作りたい 2016/09/05 16:31
いろいろな本・サイトを拝見しましたが、一番わかりやすいです。
最初から最後まで夢中になって読みました。
ありがとうございました。
by ささ 2016/09/08 14:50
>アプリが作りたいさん
ご丁寧にありがとうございます。
>さささん
嬉しいコメントありがとうございます。お役に立てたようで良かったです!
by Nobuo@管理人 2016/09/08 15:41
わかりやすい説明のおかげで最後までたどり着きました。
ありがとうございます。
by nok******* 2016/10/09 14:13
分かり易い解説ありがとうございました。
次はアプリを作りたくなるのが人情と言うもの。
APIリファレンスの使い方や画像表示切替など
ご解説くださればありがたいです。
by take 2016/10/28 13:36
ありがとうございます。
Androidアプリの作り方なら、kindle本「Androidアプリを作ろう」を参考にして下さい。
有料(900円)ですが、おかげさまで好評をいただいております。
→http://nobuo-create.net/my-book/
by Nobuo@管理人 2016/10/28 16:06
親クラスのメソッドを書き替えてしまうオーバーライドと、親クラスのメンバにアクセスするsuperを上手く使って、
つまりメソッドとメンバで方法が違うよ、と。ということはメソッドとメンバを理解していなければならないと。手段と構成ということ?
by 匿名 2019/08/27 10:29
一番わかりやすいです。ありがとうございます。
CarTestクラスの実行結果ですが
最後の残りのガソリン量は70かと思いました。
by 匿名 2022/09/02 11:53