アルゴリズムとプログラミング (Algorithms and Programming)
description
Transcript of アルゴリズムとプログラミング (Algorithms and Programming)
アルゴリズムとプログラミング
(Algorithms and Programming)
第11回:継承の実装
•継承の実装: extends キーワード コンストラクタ•継承とメソッドのオーバーライド,可視性•抽象クラス (abstract キーワード )
•継承の実装: 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() {
処理 ;
}
}
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(" 離陸! ");
}
}
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 クラスのフィールドとメソッドを暗黙的に継承している。
extends キーワードが無い全てのクラスは、自動的に Objectクラスのサブクラスとなる。従って、全てのクラスは Object クラスのフィールドとメソッドを暗黙的に継承している。
Vehicle( 乗り物 )- speed: double
# changeSpeed(s:double)# getSpeed(): double
Plane- altitude: double
# takeOff ()# land ()
Objectクラス
継承とコンストラクタ
サブクラスのコンストラクタを呼び出すと..
1.まずスーパクラスのコンストラクタが実行される(何も指定しなければデフォルトコンストラクタが呼ばれる.引数は無し)
2.次にサブクラスのコンストラクタが実行される
class X {
int x;
X() {
x = 100;
}
}
class Y extends X {
int y;
Y() {
y = 200;
}
}
class X {
int x;
X() {
x = 100;
}
}
class Y extends X {
int y;
Y() {
y = 200;
}
}
サブクラスのコンストラクタ( 例 )SampleAP0901.java
ここに super(); が省略されていると考える
class SampleAP0901 {
public static void main(String[] args) {
Y o = new Y();
System.out.println("x= " + o.x );
System.out.println("y= " + o.y );
}
}
class SampleAP0901 {
public static void main(String[] args) {
Y o = new Y();
System.out.println("x= " + o.x );
System.out.println("y= " + o.y );
}
}
サンプルプログラム ( 続き )SampleAP0901.java続き
実行結果
x= 100
y= 200
親のコンストラクタを指定する場合
Superキーワード
class X { int x; X(int a) { x = a; }}class Y extends X { int y; Y(int a, int b) { super(a); y = b; }}
class X { int x; X(int a) { x = a; }}class Y extends X { int y; Y(int a, int b) { super(a); y = b; }}
SampleAP0902.java
コンストラクタで superを使うときは最初の行でしか使えない!コンストラクタで superを使うときは最初の行でしか使えない!
( this キーワードとの併用は不可)
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 );
}
}
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 );
}
}
SampleAP0902.java続き
実行結果
x= 1
y= 2
class X {
int x;
X() {
x = 100;
}
}
class Y extends X {
int y;
Y() {
y = 200;
}
}
class X {
int x;
X() {
x = 100;
}
}
class Y extends X {
int y;
Y() {
y = 200;
}
}
SampleAP0901.java(再)
ここに super(); が省略されていると考える
暗黙の親コンストラクタ呼び出し
継承を禁止する final キーワード
final class X {
int x;
}
class Y extends X {
int y;
}
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原則:ポリモーフィズム
乗り物
# 動力を始動する ()
飛行機
# 動力を始動する ()
自動車
# 動力を始動する ()
ジェット機
# 動力を始動する ()
プロペラ機
# 動力を始動する ()
操作名は同じだが、実際の操作内容はそれぞれ異なる
操作名は同じだが、実際の操作内容はそれぞれ異なる
メソッドのオーバーライド
ジェット機クラスのインスタンスを生成する
:ジェット機
このインスタンスを乗り物オブジェクトと見なす(乗り物オブジェクト変数 v1 に格納する)
v1. 動力を始動する ()
動力を始動する () メッセージを送るこの記法は、ジェット機に限らず、プロペラ機にも自動車にも、将来的に追加される乗り物にもそのまま変更なく使える。上位概念(スーパークラス)オブジェクトに対する
操作として記述しておくと、サブクラスの細かい修正や追加などに対して強いプログラムになる(保守性が高い)
乗り物オブジェクトの操作が呼び出されるように記述されているが、自動的にジェット機オブジェクトに対する操作が呼び出される
乗り物 v1 = new ジェット機 ();
new ジェット機 ();
ジェット機クラスのインスタンスへの参照乗り物クラス
ジェット機クラスのインスタンスを生成する
:ジェット機
このインスタンスをジェット機オブジェクト変数 j1 に格納する
j 1 . 動力を始動する ()
動力を始動する () メッセージを送る
この記法では、プロペラ機や自動車に変更したり、さらには将来的に追加される乗り物に対しては、そのままでは使えない。プログラムの記述を変更する必要がある!
new ジェット機 ();
ジェット機 j1 = new ジェット機 ();
ジェット機クラスのインスタンスへの参照ジェット機クラス
その効果: サブクラスの細かい修正や追加などに対して強い(保守性が高い)プログラムになる
ポリモーフィズム (polymorphism) の意味: 1つのオブジェクトが複数の型を持つ ← 継承により実現ポリモーフィズムの活用の仕方: 上位概念(スーパークラス)への操作としてプログラムを記述する
ポリモーフィズムの意味と効果
オブジェクト指向プログラミングの有効性!
class X { // スーパー(親)クラス int x;
}
class Y extends X { // サブ(子)クラス int y;
}
class SampleAP1001 {
public static void main(String[] args){
X o = new Y();// サブクラス Y のインスタンスを親クラス X
} // の参照型変数へ代入できる!}
class X { // スーパー(親)クラス int x;
}
class Y extends X { // サブ(子)クラス int y;
}
class SampleAP1001 {
public static void main(String[] args){
X o = new Y();// サブクラス Y のインスタンスを親クラス X
} // の参照型変数へ代入できる!}
参照型変数への代入 ( 例 )SampleAP1001.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; // 具体的な定義はサブクラスで与える。
}
}
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 ); }}
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() ); }}
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() ); }}
SampleAP1002.java続き
o1 の面積は 0.0o2 の面積は 50.0o3 の面積は 100.0
o1 の面積は 0.0o2 の面積は 50.0o3 の面積は 100.0
実行結果
引数に与えた数値は o1 ~ o2まで全て同じだが、それぞれオーバーライドされた getArea() メソッドが、異なる処理を実行している。
抽象クラス: 抽象メソッドを持つためオブジェクト生成できないクラス
乗り物- スピード# スピードを変える ()# スピードを表示する ()
飛行機- 高度
# 離陸する ()# 着陸する ()# 高度を表示する ()
飛行機クラスでは、依然としてスピードを表示する () 操作は必須であり、乗り物クラスは使われる。
飛行機クラスでは、依然としてスピードを表示する () 操作は必須であり、乗り物クラスは使われる。
クラス名をイタリックにすると抽象クラス
クラス名をイタリックにすると抽象クラス
乗り物クラスのインスタンスは存在しないことが保証される
乗り物クラスのインスタンスは存在しないことが保証される
抽象クラスの実装
親クラスではメソッド名だけ定義して、子クラスにおいて、オーバーライドにより具体的な処理内容を記述する
親クラスではメソッド名だけ定義して、子クラスにおいて、オーバーライドにより具体的な処理内容を記述する
抽象メソッド: abstract キーワード具体的な処理内容が与えられていないため、インスタンスの作成は不可
abstract class Shape { // 抽象クラス double a; double b;
Shape(double x, double y) { a = x; b = y; } // 抽象メソッドとして定義(この方が自然) abstract double getArea();
}
abstract class Shape { // 抽象クラス double a; double b;
Shape(double x, double y) { a = x; b = y; } // 抽象メソッドとして定義(この方が自然) abstract double getArea();
}
SampleAP1003.java
抽象クラスの使用例
•抽象メソッドが1つでもあるとそのクラスは抽象クラス→サブクラスで具体的な処理内容を与えて使用する
•抽象クラスだからといって、全てが抽象クラスである必要は無い
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 ); }}
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と同じ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() ); }}
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() ); }}
SampleAP1003.java続き
抽象クラスのインスタンス化を削除
まとめ1
•継承の実装: extends キーワード•継承とコンストラクタ : super キーワード•継承の禁止: final キーワード
•継承の実装: extends キーワード•継承とコンストラクタ : super キーワード•継承の禁止: final キーワード
まとめ2
•継承とメソッドのオーバーライド•抽象メソッド、抽象クラス
より保守性の高いプログラムの実現
•継承とメソッドのオーバーライド•抽象メソッド、抽象クラス
より保守性の高いプログラムの実現
世の中で既に作成され公開されている各種の Javaクラスライブラリはこのような考え方で作成されている。適当なクラスを継承してカスタマイズすることにより、極めて簡単に自分独自の問題を解決することができる。