アルゴリズムとプログラミング (Algorithms and Programming) 第11回:継承の実装 •継承の実装: extends キーワード コンストラクタ •継承とメソッドのオーバーライド,可視性 •抽象クラス (abstractキーワード) 講義資料等: http://www.pe.titech.ac.jp/~watanabe/lecture/ap/index-j.html スーパークラス 継承の実装 Vehicle(乗り物) - speed: double # changeSpeed(s:double) # getSpeed(): double サブクラス Plane - altitude: double # takeOff () # land () サブクラスは、スーパークラス の全てのフィールドとメソッドを 含んでいる。 (実際にアクセスできるかは、 アクセス修飾子に従う) 継承の実装:extendsキーワード スーパークラス Vehicle(乗り物) - speed: double # changeSpeed(s:double) # getSpeed(): double サブクラス Plane - altitude: double # takeOff () # land () class Plane extends Vehicle { private double altitude; protected void takeOff() { 処理(スーパークラスのメソッドも呼べる); } protected void land() { 処理; } } スーパークラスへのアクセス スーパークラス Vehicle(乗り物) - speed: double # changeSpeed(s:double) # getSpeed(): double サブクラス Plane - altitude: double # takeOff () # land () public static void main(略) { Plane o = new Plane(); o.changeSpeed(0.0); for(int i=0;i<=300;i+=50){ o.changeSpeed(i); o.takeOff(); } System.out.println("離陸!"); } } 全てのクラスのスーパークラス Objectクラス extendsキーワードが 無い全てのクラスは、自 動的にObjectクラスの サブクラスとなる。従っ て、全てのクラスは Objectクラスのフィー ルドとメソッドを暗黙的に 継承している。 Objectクラス Vehicle(乗り物) - speed: double # changeSpeed(s:double) # getSpeed(): double Plane - altitude: double # takeOff () # land () 継承とコンストラクタ サブクラスのコンストラクタを呼び出すと.. 1. まずスーパクラスのコンストラクタが実行される (何も指定しなければデフォルトコンストラクタが呼ばれる.引数は無し) 2. 次にサブクラスのコンストラクタが実行される サブクラスのコンストラクタ(例) SampleAP0901.java class int X() x } } class int Y() y } } X { x; { = 100; Y extends X { y; ここにsuper();が省略 { = 200; されていると考える サンプルプログラム(続き) SampleAP0901.java続き class SampleAP0901 { public static void main(String[] args) { Y o = new Y(); System.out.println("x= " + o.x ); System.out.println("y= " + o.y ); } } 実行結果 x= 100 y= 200 親のコンストラクタを指定する場合 Superキーワード SampleAP0902.java class X { int x; X(int a) { x = a; } } class Y extends X { int y; Y(int a, int b) { super(a); y = b; } } (thisキーワードとの併用は不可) コンストラクタでsuperを使うときは 最初の行でしか使えない! SampleAP0902.java続き class SampleAP0902 { public static void main(String[] args) { Y o = new Y( 1, 2 ); System.out.println("x= " + o.x ); System.out.println("y= " + o.y ); } } 実行結果 x= 1 y= 2 暗黙の親コンストラクタ呼び出し SampleAP0901.java(再) class int X() x } } class int Y() y } } X { x; { = 100; Y extends X { y; ここにsuper();が省略 { = 200; されていると考える 継承を禁止するfinalキーワード final class X { int x; サブクラスの宣言を禁止! } class Y extends X { int y; } コンパイルエラー! final宣言したクラスは、extendsで サブクラスを作ることが禁止される メソッドのオーバーライド オーバーライド(override) 親クラスと子クラスのそれぞれに、 メソッド名、引数、戻り値が全て同一で 内容が異なるメソッドを定義すること 既出 オーバーロード (overload) 混同注 意! ひとつのクラス内に、メソッド名が同じ で、引数の型及び数が異なるメソッドを 定義すること オーバーライドの目的 Vehicle(エンジン付き乗り物) - speed: double # getSpeed(): double # startEngine () Plane - altitude: double # takeOff () # startEngine () もともと、サブクラスにはスー パークラスのフィールドとメ ソッドが全て自動的に引き継 がれている。 しかし、引き継がれているメ ソッドの処理内容を、サブク ラスで再定義(変更)したい場 合がある 。 オーバーライドの必要性 オーバーライドと可視性 子クラスでオーバーライドするメソッドの可視性 は、親クラスのメソッドの可視性により制限される オーバーライドされる スーパークラスのメソッド に指定されている修飾子 オーバーライドするサブクラスのメソッド public public指定が必要 protected protectedかpublicが必要 private アクセス不可につき、オーバーライド不可 無指定 private指定は不可 親クラスでprotectedが指定されているメソッドを子クラスでオーバーライドするにはprotectedかpublic指定が必要 親・子クラスにおける オブジェクト参照型変数の互換性 Javaのきまり: 型の違いに厳しいJavaですが.. •子クラスのインスタンスを指すオブジェ クト参照型変数を、親クラスの参照変数 に代入することができる。 •代入後も、インスタンスの出身が子クラ スであることを忘れずに記憶しておく仕 組みになっている。 1つのオブジェクトが、あたかも複数の型を持 つかのように見せることができる。 オブジェクト指向3原則:ポリモーフィズム (メソッドのオーバーライドと参照型変数の 互換性によって実現される) 乗り物 飛行機 ジェット機 ジェット機クラスのインスタン スを、乗り物オブジェクトとして 扱うことができる。 自動車 プロペラ機 ジェット機は飛行機でも あり、乗り物でもある ジェット機クラスのインスタン スに対する操作を、乗り物に 対する操作として記述できる このような記述の仕方に どんなメリットがあるの? 乗り物 #動力を始動する() 飛行機 自動車 #動力を始動する() ジェット機 #動力を始動する() #動力を始動する() プロペラ機 #動力を始動する() 操作名は同じだ が、実際の操作 内容はそれぞれ 異なる メソッドのオーバーライド ジェット機クラスのインスタンスを生成する :ジェット機 new ジェット機(); このインスタンスを乗り物オブジェクトと見なす (乗り物オブジェクト変数 v1 に格納する) 乗り物 v1 = new ジェット機(); 乗り物クラス ジェット機クラスのインスタンスへの参照 動力を始動する()メッセージを送る v1.動力を始動する() 乗り物オブジェクトの操作が呼び出 されるように記述されているが、自動 的にジェット機オブジェクトに対する 操作が呼び出される この記法は、ジェット機に限ら ず、プロペラ機にも自動車にも、 将来的に追加される乗り物に もそのまま変更なく使える。 上位概念(スーパークラス)オブジェクトに対する操作と して記述しておくと、サブクラスの細かい修正や追加な どに対して強いプログラムになる(保守性が高い) ジェット機クラスのインスタンスを生成する :ジェット機 new ジェット機(); このインスタンスをジェット機オブジェクト変数 j1 に格納する ジェット機 j1 = new ジェット機(); ジェット機クラス ジェット機クラスのインスタンスへの参照 動力を始動する()メッセージを送る j1.動力を始動する() この記法では、プロペラ機や自動車に変更したり、さらに は将来的に追加される乗り物に対しては、そのままでは 使えない。プログラムの記述を変更する必要がある! ポリモーフィズムの意味と効果 ポリモーフィズム(polymorphism)の意味: 1つのオブジェクトが複数の型を持つ ← 継承により実現 ポリモーフィズムの活用の仕方: 上位概念(スーパークラス)への操作としてプログラ ムを記述する その効果: サブクラスの細かい修正や追加などに対して強い (保守性が高い)プログラムになる オブジェクト指向プログラミングの有効性! 参照型変数への代入 (例) SampleAP1001.java class X { // スーパー(親)クラス int x; } class Y extends X { // サブ(子)クラス int y; } class SampleAP1001 { public static void main(String[] args){ X o = new Y();//サブクラスYのインスタンスを親クラスX } //の参照型変数へ代入できる! } メソッドのオーバーライド(例) SampleAP1002.java class Shape { //2次元図形の面積を表現するクラス double a; //一般に、面積を計算するには、縦×横や底辺×高さ/2など、 double b; //2つの辺の長さを与える必要があると考え、変数を2つ用意する Shape(double x, double y) { a = x; b = y; } double getArea() { //ここでは具体的な定義を与えないことにする。 return 0.0; //具体的な定義はサブクラスで与える。 } } SampleAP1002.java続き class Triangle extends Shape { //三角形 Triangle(double x, double y); super(x,y); // x,yとしては底辺と高さを与える } double getArea() { オーバーライド return ( a * b / 2 ); } } class Rectangle extends Shape { //四角形 Rectangle (double x, double y){ super(x,y); //x,yとしては各辺の長さを与える } double getArea() { オーバーライド return ( a * b ); } } SampleAP1002.java続き class SampleAP1002 { public static void main(String[] args) { Shape o1 = new Shape( 10.0, 10.0 ); Shape o2 = new Triangle( 10.0, 10.0 ); Shape o3 = new Rectangle( 10.0, 10.0 ); System.out.println("o1の面積は" + o1.getArea() ); System.out.println("o2の面積は" + o2.getArea() ); System.out.println("o3の面積は" + o3.getArea() ); } } 実行結果 o1の面積は0.0 o2の面積は50.0 o3の面積は100.0 引数に与えた数値はo1~o2まで 全て同じだが、それぞれオーバー ライドされたgetArea()メソッドが、 異なる処理を実行している。 抽象クラス: 抽象メソッドを持つためオブジェ クト生成できないクラス 乗り物 -スピード #スピードを変える() #スピードを表示する() 飛行機 -高度 #離陸する() #着陸する() #高度を表示する() クラス名をイタリックにすると 抽象クラス 乗り物クラスのインスタンスは 存在しないことが保証される 飛行機クラスでは、依然として スピードを表示する()操作は必須 であり、乗り物クラスは使われる。 抽象クラスの実装 親クラスではメソッド名だけ定義して、子ク ラスにおいて、オーバーライドにより具体的 な処理内容を記述する 抽象メソッド: abstractキーワード 具体的な処理内容が与えられていな いため、インスタンスの作成は不可 抽象クラスの使用例 SampleAP1003.java abstract class Shape { //抽象クラス double a; double b; Shape(double x, double y) { a = x; b = y; } //抽象メソッドとして定義(この方が自然) abstract double getArea(); } •抽象メソッドが1つでもあるとそのクラスは抽象クラス →サブクラスで具体的な処理内容を与えて使用する •抽象クラスだからといって、全てが抽象クラスである必要は無い SampleAP1003.java続き この部分はSampleAP1002.javaと同じ class Triangle extends Shape { //三角形 Triangle(double x, double y); super(x,y); // x,yとしては底辺と高さを与える } double getArea() { return ( a * b / 2 ); } } class Rectangle extends Shape { //四角形 Rectangle (double x, double y){ super(x,y); //x,yとしては各辺の長さを与える } double getArea() { return ( a * b ); } } SampleAP1003.java続き class SampleAP1003 { public static void main(String[] args) { Shape o2 = new Triangle( 10.0, 10.0 ); Shape o3 = new Rectangle( 10.0, 10.0 ); System.out.println("o2の面積は" + o2.getArea() ); System.out.println("o3の面積は" + o3.getArea() ); } } 抽象クラスのインスタンス化を削除 まとめ1 •継承の実装: extends キーワード •継承とコンストラクタ: superキーワード •継承の禁止: finalキーワード まとめ2 •継承とメソッドのオーバーライド •抽象メソッド、抽象クラス より保守性の高いプログラムの実現 世の中で既に作成され公開されている各種のJavaクラ スライブラリはこのような考え方で作成されている。適当 なクラスを継承してカスタマイズすることにより、極めて 簡単に自分独自の問題を解決することができる。
© Copyright 2024 ExpyDoc