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 あさやん 2015/11/17 00:02
しっかり隅々読んでいただけて嬉しいです。
誤字脱字のないように気を付けますが、今後ともどうぞよろしくお願いします。^^
by Nobuo@管理人 2015/11/17 00:41
いつも利用させていただいております。
大変わかりやすく、非常に助かっております。
“抽象化とインターフェース”についての作成も希望致します。
by 通りすがりの新人 2016/01/22 13:12
ご丁寧にコメントしていただいて、ありがとうございます。
ご期待に沿えるように頑張ります。
by Nobuo@管理人 2016/01/25 13:09
最初から、ようやくココまで来ました。
間違って記述されている所も含めて、勉強になります。
コメントは、少ないと思いますが、見てる人は、たくさん
居ると思います。
忙しいと思いますが、色々な内容をお願いします。m(_”_)m
by 自己学習中 2016/02/16 14:55
嬉しいコメントありがとうございます。
励みになります。(^^)
by Nobuo@管理人 2016/02/16 22:45
絵本の入門書を買ってきて、勉強しましたが挫折しました。初心者には絵と本文の整合性が分からず、どうしてこうなるのか解説がなく難しい言語だなと思いました。 だいぶブランクがあって、このサイトを見つけて一からやり直したらスラスラと最後まで進み、基本は理解できました。 ありがとうございました。
by Tora 2016/02/21 06:23
本日最後まで読みきることができました!android講座の方も拝見させて頂きますm(_ _)m
by kiddie 2016/02/26 01:52
他のサイトだと当たり前だろと言わんばかりにすっ飛ばされているところも丁寧に説明がのっていて、とても助かっています。
更新やコメント対応など大変だと思いますが、これからも頑張って下さい。
by 匿名 2016/06/10 17:52
とてもわかりやすく助かりました!
感謝しています。
by 名無し 2016/06/11 04:00