第7回 継承とインターフェ イス
~オブジェクト指向の真髄に挑戦!~
学習目標
継承とインターフェイスを利用したプ ログラムが書ける 継承を使う利点を説明できる
Java
で継承を使ったプログラムが書ける ポリモーフィズムを使ったプログラムが書 ける
7.1 継承
7.1.1
配列リストと連結リストの性能比較
7.1.2
継承 7.1.3 Java
で継承を使ったプログラムを書く
7.1.1 配列リストと
連結リストの性能比較
public static void main(String[] args) { long startTime;//開始時間を保存する long endTime; //終了時間を保存する //--- 配列リストの性能を測定する --- // 商品種類配列リストを生成する
ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
startTime = System.currentTimeMillis();//開始時間を測定する // 商品種類を 1 万件登録する
for(int i=0;i<10000;i++){
itemTypeArrayList.add(new ItemType(1001,"コーラ ",120));
}
endTime = System.currentTimeMillis();//終了時間を測定する
System.out.println("かかった時間は "+ (endTime - startTime) + "ミリ秒です ");
//--- 連結リストの性能を測定する --- // 商品種類連結リストを生成する
ItemTypeLinkedList itemTypeLinkedList = new ItemTypeLinkedList();
startTime = System.currentTimeMillis();//開始時間を測定する // 商品種類を 1 万件登録する
for(int i=0;i<10000;i++){
itemTypeLinkedList.add(new ItemType(1001,"コーラ ",120));
}
例題
7-1
同じ意味の数字は定数に
前回のバグの原因
オブジェクト指向以前の問題です//
商品種類を保存する配列を生成itemTypeArray = new ItemType[10];
//
商品種類を保存するための変数を初期化する ( 実は不要 ) // 何も入っていないことをnull
として扱うfor(int i=0;i<10;i++){
itemTypeArray[i] = null;
}
など、全部で4ヶ所 あります。
同じ意味の数字は定数に
「同じ意味を何度も書かない」がプロ グラムの基本ですprivate int ARRAY_SIZE = 10000;// 配列の大きさ
//
商品種類を保存する配列を生成itemTypeArray = new ItemType[ARRAY_SIZE];
//
商品種類を保存するための変数を初期化する ( 実は不要 ) // 何も入っていないことをnull
として扱うfor(int i=0;i<ARRAY_SIZE;i++){
itemTypeArray[i] = null;
配列の大きさを 保存しておく変数 を作ります
変更する必要が なくなりますね。
例題
7-1
(ItemTypeArrayList.java)
① ほとんど同じコードが 2 度
public static void main(String[] args) { long startTime;//開始時間を保存する long endTime; //終了時間を保存する //--- 配列リストの性能を測定する --- // 商品種類配列リストを生成する
ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
startTime = System.currentTimeMillis();//開始時間を測定する // 商品種類を 1 万件登録する
for(int i=0;i<10000;i++){
itemTypeArrayList.add(new ItemType(1001,"コーラ ",120));
}
endTime = System.currentTimeMillis();//終了時間を測定する
System.out.println("かかった時間は "+ (endTime - startTime) + "ミリ秒です ");
//--- 連結リストの性能を測定する --- // 商品種類連結リストを生成する
ItemTypeLinkedList itemTypeLinkedList = new ItemTypeLinkedList();
startTime = System.currentTimeMillis();//開始時間を測定する // 商品種類を 1 万件登録する
for(int i=0;i<10000;i++){
itemTypeLinkedList.add(new ItemType(1001,"コーラ ",120));
}
同じ仕事
例題
7-1
(Example7_1.java)
② どうしたらメソッド化でき るか?
今回は、この2つの仕事のメソッド化 を考えます 考えてみましょう
仕事が同じ意味をもつかどう か
< A >
•
配列リストの性能を測る•
配列リストを生成する•
開始時間を測定する•
配列リストに1
万件追加する•
終了時間を測定する•
かかった時間を表示する< B >
•
連結リストの性能を測る•
連結リストを生成する•
開始時間を測定する•
連結リストに1
万件追加する•
終了時間を測定する仕事は同じ意味を持つ
<仕事を>
•
「リスト」の性能を測る•
「リスト」を生成する•
開始時間を測定する•
「リスト」1
万件追加する•
終了時間を測定する•
かかった時間を表示する
ただし、「リスト」という意味のカタ マリができた場合型が違う
型が違うので、今までの方法ではまと められない//---
配列リスト版 ---ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
・・・
itemTypeArrayList.add(new ItemType(1001,"
コーラ "));//---
連結リスト版 ---ItemTypeLinkedList itemTypeLinkedList = new ItemTypeLinkedList();
・・・
itemTypeLinkedList.add(new ItemType(1001,"
コーラ "));まとめられない
I t emTypeAr r ayLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) Mai n
+ mai n( )
1 1
I t emTypeLi nkedLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) 1
1
1 1
1 1
型が違う
問題の原因は配列リストと連結リスト を違う型として捉えていること 「リスト」という意味は同じだが、違うク ラス
意味は同じなのに
7.1.2 継承
① 継承
② 継承をクラス図で表現する① 継承
「リスト」という意味のカタマリができれば、その カタマリに対して性能を測るプログラムができる
継承
を使って型の違うクラスの意味のカタマリをつくる
<仕事を>
•
「リスト」の性能を測る•
「リスト」を生成する•
開始時間を測定する•
「リスト」1
万件追加する•
終了時間を測定する•
かかった時間を表示する継承
共通の意味を持つクラス
(商品種類のリスト)
I t emTypeArr ayLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay()
I t emTypeLi nkedLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( )
共通の意味をクラスに
I t emTypeLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( )
抽象化
「リスト」という抽象クラスを定義す るI t emTypeLi nkedLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( )
I t emTypeAr r ayLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) I t emTypeLi st
+ add( ) + del et e( ) + sear ch( ) + di spl ay( )
② クラス図で表現する
ItemTypeLinkedList
はItemTypeList
のサブクラス
ItemTypeList
はItemTypeArrayList
の スーパークラス同じ意味に見える
Example
は、新しい語彙である「リスト」クラスに対してプログラムするこ とができます
配列リストか連結リストか意識しなくて済 む
より意味が明確なプログラムに
I t emTypeLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( )
I t emTypeAr r ayLi st + add( )
I t emTypeLi nkedLi st + add( )
Mai n + mai n( )
1 2
1 2
7.1.3 Java で継承を
使ったプログラムを書く
① スーパークラスの変数への代入 ② Java
の記法
③ 抽象クラスとインターフェイス
④ 継承vs
インターフェイス① スーパークラス の変数への代入
//---
配列リスト版 ---ItemTypeArrayList itemTypeArrayList = new ItemTypeArrayList();
//---
連結リスト版 ---ItemTypeLinkedList itemTypeLinkedList = new ItemTypeLinkedList();
itemTypeArrayList
ItemTypeArrayList
インスタンスitemTypeLinkedList
ItemTypeLinkedList
インスタンス基本的に
① スーパークラス の変数への代入
//---
配列版 ---ItemTypeList itemTypeList = new ItemTypeArrayList();
//---
連結リスト版 ---ItemTypeList itemTypeList = new ItemTypeLinkedList();
itemTypeList ItemTypeArrayList
インスタンス
ItemTypeLinkedList
インスタンススーパークラスの変数には サブクラスのインスタンスも 代入することができる
入っている
インスタンスによって切り替 わる
ItemTypeList itemTypeList;//スーパークラスの変数を用意する //--- 配列版 ---
itemTypeList = new ItemTypeArrayList();//配列版インスタンスを代入
itemTypeList.add(new ItemType(1001,"コーラ ")); // 配列版インスタンスに追加され ます
//--- 連結リスト版 ---
itemTypeList = new ItemTypeLinkedList();// 連結リスト版インスタンスを代入
itemTypeList.add(new ItemType(1001,“コーラ” )); // 連結リスト版インスタンスに追 加されます
変数に入っているインスタンスによって、自動的に切り替えられます
Example
は対象を考える必要はなくなり、コードが共通化できます入っている
インスタンスによって切り替 わる
itemTypeList
[5]
[4]
[3]
[2]
[1]
[0]
102番地 コーラ
22(id)
null ソーダ
23(id)
itemTypeList add()
add()
ItemTypeArrayList
インスタンスItemTypeLinkedList
インスタンス② Java の文法 ( スーパークラ ス )
// 商品種類リストスーパークラス
public class ItemTypeList { //
商品種類を追加するメソッドpublic void add(ItemType addItemType){
//
何も書かないくてよい}
//
商品種類を表示するメソッド public void display(){//
何も書かないくてよい}
…
スーパークラスには特別なことを 記述する必要がありませんが、
メソッドは空でも定義しておく
例題
7-2
(ItemTypeList.java)
② Java の文法 ( サブクラス )
// 商品種類リスト配列実装クラス
public class ItemTypeArrayList extends ItemTypeList{
private int ARRAY_SIZE = 10;//
配列の大きさprivate ItemType[] itemTypeArray;// 商品種類を保存する配列 // 商品種類を追加するメソッド
public void add(ItemType addItemType){
… }
…}ItemTypeList
を継承 することを宣言しますメソッドを実装します
(スーパークラスと同じ
メソッド名にする必要があります)
例題
7-2
(ItemTypeArrayList.java
)
これでメソッド化できる
引数にスーパークラスを定義すること で、どちらのサブクラスがきても同じ 意味として扱えるので、メソッド化す ることができる/**
* 商品種類リストの性能を測る
*/
private static void performanceTest(ItemTypeList itemTypeList){
・・・・・・
// 商品種類を 1 万件登録する for(int i=0;i<10000;i++){
itemTypeList.add(new ItemType(1001,"
コーラ ",120));}
例題
7-2
(ItemTypeList.java)
③ 抽象クラスとインターフェ イス
public class ItemTypeList { …
//商品種類を表示するメソッド public void display(){
} … }
スーパークラス
public class ItemTypeArrayList extends ItemTypeList{
// 商品種類を表示するメソッド
public void disp
r ay(){for(int i=0;i<ARRAY_SIZE;i++){
if(itemTypeArray[i] != null){
System.out.println(itemTypeArr…
} } } … }
サブクラス
メソッド名を間違えるとどうなるかサブクラスで実装されていな い
サブクラスで実装されていないと、自 動的にスーパークラスのメソッドが実 行されてしまいますpublic class ItemTypeList { …
//商品種類を表示するメソッド public void display(){
} …
スーパークラス
ItemTypeList itemTypeList = new ItemTypeArrayList();
//商品種類を追加する
itemTypeList.add(new ItemType(1001,"
コーラ "));// 商品種類リストを表示する
itemTypeList.display();
サブクラス
public class ItemTypeArrayList extends ItemTypeList{
??
実行!
何もおこらない
メソッド名の間違いを防ぐ
コンパイルは通り、プログラムは動い てしまうので、バグの発見が大変です display()
メソッドはスーパークラスでは空にしてあるので、必ずサブクラス で実装して欲しいです
サブクラスで実装することを保証する方法があります
抽象クラス
// 商品種類リストスーパークラス
public class ItemTypeList { …
//商品種類を表示するメソッド public void display(){
} }
// 商品種類リストスーパークラス
public abstract class ItemTypeList { …
// 商品種類を表示するメソッドの定義 public abstract void display();
}
空実装 定義だけする
例題
7-2
(ItemTypeList.java)
例題7-3
(ItemTypeList.java)
「定義」と「実装」
public abstract class ItemTypeList { …
//商品種類を表示するメソッドの定義 public abstract void display();
}
スーパークラス
public class ItemTypeArrayList extends ItemTypeList{
// 商品種類を表示するメソッド public void display(){
for(int i=0;i<ARRAY_SIZE;i++){
if(itemTypeArray[i] != null){
System.out.println(itemTypeArr…
} } }
サブクラス
(ItemTypeList.java)
例題7-3
「定義」ーメソッドを定義する
「実装」ーメソッドを実現する定義と実装を分けることの利 点
定義と実装を分けることの利点を考え てみましょう目的と手段を分離する
「定義」ーメソッドを定義する(目 的)
「実装」ーメソッドを実現する(手 段)利用するクラスは「定義」に注目したプログラムが書ける
意味が明確なプログラムが書ける
抽象クラス
定義ができるのは「抽象クラス」 インスタンス化できないクラス
普通のクラスでは、実装しかできない
public abstract class ItemTypeList { …
//
商品種類を表示するメソッドの定義 public abstract void display();}
インターフェイス
Java
ではメソッドの定義だけする方法 として、インターフェイスが使える 例題
7-4
抽象クラスとほとんど変わりません 抽象クラスとの違いは
変数がもてない
定義しかできない(実装ができない)
インターフェイスを使う
// 商品種類リスト インターフェイス版
public interface ItemTypeList {
// 商品種類を追加するメソッドの定義public void add(ItemType addItemType);
…
}スーパークラス
// 商品種類リスト配列実装クラス
public class ItemTypeArrayList implements ItemTypeList{
// 商品種類を追加するメソッド
public void add(ItemType addItemType){
//
実装しますサブクラス
インターフェイスは
メソッドが定義と決まっているので
abstract
は書きません例題
7-4
(ItemTypeList.java)
④ 抽象クラス
VS インターフェイス
機能で考えた場合どちらでも良い場合 が多い 抽象クラスでは変数や実装ができる
インターフェイスは多重継承ができる
余裕のある人は、意味的な違いを考えてみましょう
7.2 if 文 vs ポリモーフィズム
7.2.1
実装クラスの名前を表示する 7.2.2
どのように実装するか
① if
文で実装する ② インスタンスの違いで分岐する
7.2.3 if
文vs
ポリモーフィズム7.2.1
実装クラスの名前を表示した い
performanceTest
メソッドの始めで、ど の実装クラスなのか表示するようにし ます/** * 商品種類リストの性能を測る
*/ private static void performanceTest(ItemTypeList itemTypeList){
//itemTypeList がArrayList なのかLinkedList なのかを表示する
long startTime;//
開始時間を保存する long endTime; //終了時間を保存するstartTime = System.currentTimeMillis();//開始時間を測定する // 商品種類を 1 万件登録する
① if 文で実装する
itemTypeList ItemTypeArrayList
インスタンス
ItemTypeLinkedList
インスタンス スーパークラスの変数にはサブクラスを代入できます
逆に、代入してしまうと
どのサブクラスを使っているかは
分からなくなってしまいます
itemTypeList
??
ところが...どのインスタンスが
入っているのか調べる方法
「instanceof
」演算子を使います/** * 商品種類リストの性能を測る
*/ private static void performanceTest(ItemTypeList itemTypeList){
//itemTypeList
がArrayList
なのかLinkedList
なのかを表示するif(itemTypeList instanceof ItemTypeArrayList){
System.out.println("
実装クラスの名前:ItemTypeArrayList");
}else if(itemTypeList instanceof ItemTypeLinkedList){
System.out.println("
実装クラスの名前:ItemTypeLinkedList");
}
} [ [
インスタンス名インスタンス名] instanceof [ ] instanceof [
クラス名クラス名] ]
例題
7-6
(Example7_6.java)
② インスタンスの 違いで分岐する
if
文がなくても「実装クラスの名前を表 示」はできます 考えてみましょう
Mai n + mai n( )
I t emTypeLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) + get Name( )
1 2
1 2
I t emTypeLi nkedLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) + get Name( )
I t emTypeAr r ayLi st + add( )
+ del et e( ) + sear ch( ) + di spl ay( ) + get Name( )
クラスにメソッドを加える
実装クラス名を得るメソッドを作りま す商品種類リストクラスに メソッドを加えます
インスタンスに場合分けを書 く
// 商品種類リスト 抽象クラス
public abstract class ItemTypeList { ...
//実装クラスの名前を得るメソッド
public abstract String getName();
}
// 商品種類リスト配列実装クラス
public class ItemTypeArrayList extends ItemTypeList{
…
//実装クラスの名前を得るメソッド public String getName(){
return "ItemTypeArrayList";
} }
// 商品種類リスト連結リスト実装クラス
public class ItemTypeLinkedList extends ItemTypeList{
…
//実装クラスの名前を得るメソッド public String getName(){
return "ItemTypeLinkedList";
}
スーパークラスで 定義します
サブクラスで実装します
例題
7-6
(ItemTypeList.java)
(ItemTypeArrayList.java)
インスタンスで場合分けされ る
/** * 商品種類リストの性能を測る
*/ private static void performanceTest(ItemTypeList itemTypeList){
//itemTypeList
がArrayList
なのかLinkedList
なのかを表示するSystem.out.println("
実装クラスの名前: "+itemTypeList.getName());… }
itemTypeList
に入っているインスタンスによって例題
7-6
(Example7_6.java)
「ポリモーフィズム」という仕組み7.2.3 if 文 VS ポリモーフィ ズム
どちらがよいのか議論してみましょうif 文 VS ポリモーフィズム
if
文は拡張性が低い 要素が増えるたびに
else if
文を追加しなけれ ばならない ポリモーフィズムなら
Example
を変えないで 実装クラスを追加できる
ポリモーフィズムはクラスが増える 全部の
if
文をポリモーフィズムに直したらク ラスが多くなってよけい理解しにくくなるバランス