第12回 汎用的なリストとJavaAPI

第12回 汎用的なリストと
JavaAPI
~クラスの再利用について考えよう
~
学習目標

クラスの再利用について議論できる




汎用的なクラスとはどういうものか説明できる
汎用的なクラスを作るために、効果的に継承を利用す
ることを議論できる
継承と委譲による設計の違いをクラスの再利用という
側面から説明できる
簡単なコレクションJavaAPIを利用したプログラム
が書ける


クラスのキャストを正しく使ったプログラムが書ける
Object型の存在を説明できる
12.1 汎用的なリスト




12.1.1
12.1.2
12.1.3
12.1.4
今回考える題材
再利用を考える
汎用的なリストの実装
キャスト
12.1.1 今回考える題材

リストによる1対多の実装

商品種類と商品種類リスト
商品種類リスト
商品種類
- 商品番号
- 商品名
- 価格
0..n
+
+
1 +
+
追加()
削除()
検索()
表示()
今回考える題材

リストによる1対多の実装はよくあるケース

今回は、金の種類も扱う時を考える
金種類リスト
金種類
- 価値
0..n
+
+
1 +
+
追加()
削除()
検索()
表示()
商品種類リスト
商品種類
- 商品番号
- 商品名
- 価格
0..n
+
+
1+
+
追加()
削除()
検索()
表示()
構造は同じ
12.1.2 再利用を考える

金種類リストと商品種類リストはほとんど
同じコードが書かれている
//金種類リストクラス
public class MoneyTypeList {
例題12-1
(MoneyTypeList.java) //商品種類リストクラス
例題12-1
(ItemTypeList.java)
public class ItemTypeList {
private int ARRAY_SIZE = 20;
private MoneyType[] moneyTypeArray;
private int size = 0;
private int ARRAY_SIZE = 20;
private ItemType[] itemTypeArray;
private int size = 0;
//コンストラクタ
public MoneyTypeList() {
moneyTypeArray = new MoneyType[ARRAY_SIZE];
}
//コンストラクタ
public ItemTypeList() {
itemTypeArray = new ItemType[ARRAY_SIZE];
}
//リストに金種類を追加する
public void add(MoneyType newMoneyType){
moneyTypeArray[size] = newMoneyType;
size++;
}
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeArray[size] = newItemType;
size++;
}
再利用をできるように

共通部分、異なる部分を挙げてみよう
//商品種類リストクラス
public class ItemTypeList {
//金種類リストクラス
public class MoneyTypeList {
private int ARRAY_SIZE = 20;
private MoneyType[] moneyTypeArray;
private int size = 0;
private int ARRAY_SIZE = 20;
private ItemType[] itemTypeArray;
private int size = 0;
配列の型
//コンストラクタ
public MoneyTypeList() {
moneyTypeArray = new MoneyType[ARRAY_SIZE];
}
//リストに金種類を追加する
public void add(MoneyType newMoneyType){
moneyTypeArray[size] = newMoneyType;
size++;
}
//コンストラクタ
public ItemTypeList() {
itemTypeArray = new
ItemType[ARRAY_SIZE];
}
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeArray[size] = newItemType;
size++;
}
引数
①問題の分析

プログラムが共通の点

追加、削除のアルゴリズム
アルゴリズムの意味は同じ

プログラムが異なる点


取り扱う配列の型が違う
取り扱う引数の型が違う
取り扱う要素の型が違うこ
とが問題
問題の分析

型が違う→意味が違う

どう違うのか



商品種類リストに商品種類を追加する
金種類リストに金種類を追加する
可読性(意味が明確)をすこし犠牲にして、
再利用性を高める

リストに「要素」を追加する
要素の型が違うことが問題

型を同じにするためには

継承を使うことによって、「プログラムの意味」
をに注目した「リスト」という語彙ができた
商品種類リスト
Main
+
+
+
+
追加()
削除()
検索()
表示()
商品種類配列リスト
商品種類連結リスト
リストの立場から考える

汎用的なリストにとっての意味を考える
金種類
- 価値
汎用リスト
商品種類
- 商品番号
- 商品名
- 価格
+ 追加()
+ 削除()
共通の意味

商品種類も金種類もリストから見れば、同
じ「要素」という意味がある

継承を利用し「要素」という語彙を作る
汎用リスト
リスト要素
+ 追加()
+ 削除()
金種類
- 価値
商品種類
- 商品番号
- 商品名
- 価格
12.1.3 汎用的なリストの実装

①Object型を利用する

ここでは、List要素クラスとしてObject型を考え
る
汎用リスト
Object
+ 追加()
+ 削除()
金種類
- 価値
商品種類
- 商品番号
- 商品名
- 価格
何故Object型を使うのか

Javaでは「すべてのクラスは自動的に
Objectクラスを継承する」決まりになってい
る

extendsと書かなくても自動的にObject型を継
承する
List要素クラスを定義して、継承する必要がなく、
すべてのオブジェクトを格納できるListになる

②汎用的なListのリスト
//汎用リストクラス
public class ObjectList {
private int ARRAY_SIZE = 20;
private Object[] objectArray;
private int size;
例題12-2
(ObjectList.java)
//配列の大きさ
//Objectを保存する配列
//要素数
//コンストラクタ
public ObjectList() {
objectArray = new Object[ARRAY_SIZE];//配列を初期化する
}
//リストにObjectを追加する
public void add(Object newObject){
objectArray[size] = newObject;
size++;
}
汎用的なListの利用

例題12-2
Objectクラス
を省略
金種類リスト
金種類
- 価値
0..n
+
+
1 +
+
追加()
削除()
検索()
表示()
商品種類リスト
商品種類
- 商品番号
- 商品名
- 価格
0..n
+
+
1 +
+
追加()
削除()
検索()
表示()
今までの共通部分を
まとめた汎用リストクラス
汎用リスト
+ 追加()
+ 削除()
重複コードがなくなる
例題12-2
例題12-2
(ItemTypeList.java)
//商品種類リストクラス (MoneyTypeList.java) //金種類リストクラス
public class ItemTypeList {
public class MoneyTypeList {
private ObjectList itemTypeList;
private ObjectList moneyTypeList;
//コンストラクタ
public ItemTypeList() {
itemTypeList = new ObjectList();
}
//コンストラクタ
public MoneyTypeList() {
moneyTypeList = new ObjectList();
}
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeList.add(newItemType);
}
//リストに金種類を追加する
public void add(MoneyType newMoneyType){
moneyTypeList.add(newMoneyType);
}
12.1.4 キャスト


①検索に対応する
②型変換(キャスト)
①検索に対応する

汎用リストでは検索や表示ができない

理由を考えてみよう
検索や表示が
汎用化できない理由
①検索に対応する

検索に対応するためにリストにアクセスす
るメソッドを追加する


size()
get(int index)
検索対応メソッド
//汎用リストクラス
public class ObjectList {
private int ARRAY_SIZE = 20;
private Object[] objectArray;
private int size;
例題12-2
(ObjectList.java)
//配列の大きさ
//Objectを保存する配列
//要素数
//コンストラクタ
public ObjectList() {
objectArray = new Object[ARRAY_SIZE];//配列を初期化する
}
//途中省略
//リストの要素数を取得する
public int size(){
return size;
}
//index番目の要素を得る
public Object get(int index){
return objectArray[index];
}
}
②型変換(キャスト)
例題11-2
(ItemTypeList.java)
//ItemTypeListより抜粋
//指定された商品番号を持つ商品種類を検索する
public ItemType search(int searchID){
int len = itemTypeList.size();
//リストの大きさ
for(int i=0;i<len;i++){
ItemType itemType = (ItemType)itemTypeList.get(i);//i番目の要素取得
if(itemType.getId() == searchID){//idを比較
return itemType;//見つかった
ここに注目!
}
}
//見つからなかった
return null;
}
型変換(キャスト)

取得したi番目の要素はObject型
汎用リストは要素をObject型で扱う


欲しい要素はItemType型
Object型として扱われているが実際はItemType型

型変換(キャスト)が必要
ItemType itemType = (ItemType)itemTypeList.get(i);
もちろん、このようにプログラム
を書いてもよい→
Object object = itemTypeList.get(i);
ItemType itemType = (ItemType)object;
クラス・キャスト

オブジェクトの見え方を変換する


実際のオブジェクトは変わらないことに注意
型変換をする条件


変換するクラスが継承関係にあること
もちろんそのクラスのインスタンスでなければダメ
コーラ:ItemType
id=1001
name=コーラ
price=120円
Object型として見る
このオブジェクトに
対して
ItemType型として見る
Object
ItemType
- id
- name
- price
自動キャスト

下記の追加メソッドは何故うまくいくか
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeList.add(newItemType);
}
itemTypeList.add()の引数
にはObject型が必要では?
ItemType→Objectのキャストは自動的に行われるためうまくいく
もちろん、このようにプログラム
を書いてもよい→
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeList.add((Object)newItemType);
}
キャスト まとめ

自動的キャストと明示的キャスト


サブクラス→スーパークラスの変換は自動的
にキャストされる
スーパークラス→サブクラスの変換は明示的
なキャストが必要
Object
自動的
ItemType
- id
- name
- price
明示的
12.2 継承VS委譲



12.2.1 継承による設計
12.2.2 委譲による設計
12.2.3 継承VS委譲
12.2.1 継承による設計

一つの疑問

継承を利用して解決したほうがよいのではな
いか?
汎用リスト
+ 追加()
+ 削除()
金種類リスト
+
+
+
+
追加()
削除()
検索()
表示()
商品種類リスト
+
+
+
+
追加()
削除()
検索()
表示()
継承による設計
12.2.2 委譲による設計

現状の設計

商品種類リスト、金種類リストが汎用Listクラ
スに要素の管理を任せている設計
金種類リスト
+
+
+
+
追加()
削除()
検索()
表示()
商品種類リスト
+
+
+
+
汎用リスト
+ 追加()
+ 削除()
追加()
削除()
検索()
表示()
責任を他のクラスに任せる設計を「委譲」といいます
継承VS委譲

それぞれの設計の利点・欠点を考える
汎用リスト
金種類リスト
+
+
+
+
追加()
削除()
検索()
表示()
商品種類リスト
+
+
+
+
+ 追加()
+ 削除()
汎用リスト
+ 追加()
+ 削除()
追加()
削除()
検索()
表示()
委譲を使った設計
金種類リスト
商品種類リスト
+
+
+
+
+
+
+
+
追加()
削除()
検索()
表示()
追加()
削除()
検索()
表示()
継承を使った設計
プログラムイメージ
委譲による設計
public class ItemTypeList {
private ObjectList objectList;
public void add(ItemType itemType){
objectList.add(itemType);
}
}
public class ItemTypeList extends ObjectList{
継承による設計
public void add(ItemType itemType){
super.add(itemType);
}
}
①継承の利点が発揮される時

クラスに共通の意味がある場合に、利用す
るプログラムが共通の意味に注目したプロ
グラムを書くことができる
共通の意味に注目できる
共通の意味に注目できる
汎用リスト
商品種類リスト
Main
リスト要素
+
+
+
+
追加()
削除()
検索()
表示()
商品種類配列リスト
+ 追加()
+ 削除()
商品種類連結リスト
金種類
- 価値
商品種類
- 商品番号
- 商品名
- 価格
②継承の利点は生かされるか
金種類リストか、商品種類リストを意識せず、汎用的なList
に対してプログラムを書く場合が果たしてあるか?
汎用リスト
利用するプログラム
???
+ 追加()
+ 削除()
金種類リスト
商品種類リスト
+
+
+
+
+
+
+
+
追加()
削除()
検索()
表示()
追加()
削除()
検索()
表示()
③プログラムの意味に注目する


金種類リストを利用するプログラムは金種類リストを追加したい
商品種類リストを利用するプログラムは商品種類リストを追加したい
金種類リスト
金種類リストを
利用するプログラム
金種類を追加する
+
+
+
+
追加()
削除()
検索()
表示()
商品種類リスト
商品種類リストを
利用するプログラム
商品種類を追加する
+
+
+
+
追加()
削除()
検索()
表示()
プログラムの意味に注目する(2)

各クラスのメソッドの意味が異なっている

目的-手段の関係ではない
汎用リスト
Objectをリストに追加する
+ 追加()
+ 削除()
金種類リスト
商品種類リスト
+
+
+
+
+
+
+
+
追加()
削除()
検索()
表示()
金種類を金種類リスト
に追加する
追加()
削除()
検索()
表示()
商品種類を商品種類リスト
に追加する
良いように見えるけど

こうして考えると、商品種類リストと金種類
リストは意味がまったく異なることが分かる


絶対に間違いということはないが、継承を使う
利点はなくなるのでは?
逆に様々な欠点が浮かび上がる


多重継承はできないことに注意する
ex)リストの実装を変更したい場合どうするか


金種類リストを連結リストでの実装に
商品種類リストを配列での実装に
12.3 JavaAPIを利用する




12.3.1
12.3.2
12.3.3
12.3.4
JavaAPI
リスト周りのAPI
JavaAPIを利用したプログラム
JavaAPIドキュメント
12.3.1 JavaAPI

Listのようなクラスはとてもよく使う


プログラミングのたびに自作するのは面倒だ
汎用的なListは再利用できる
Javaでは汎用的で便利なクラス群が用意されている
Javaクラス・ライブラリ
APIとは?

Application Programming Interface

アプリケーションプログラムを書くためのイン
ターフェイス
ライブラリ
(クラス群)
APIを通じて
ライブラリを利用する
あなたが作る
アプリケーション・
プログラム
12.3.2 リスト周りのAPI

Javaで用意されているリスト


List(Interface)
ArrayList


配列で実装されたリスト
LinkedList

List 連結リストで実装されたリスト
ArrayList
LinkedList
List

API(抜粋)

Listインターフェイスの主なメソッド




void add(Object object)
void remove(Object object)
int size()
Object get(int index)
使い方は今回作ったListと同じ
つまり、ArrayList,LinkedListクラスでこれらのメソッドが使える
LinkedList

LinkedListクラスの特別なメソッド




void
void
void
void
addFirst(Object object)
addLast(Object object)
removeLast(Object object)
removeFirst(Object object)
このメソッドを使えば、簡単にキュー、スタックを作ることが
できます
12.3.3
JavaAPIを利用したプログラム
import java.util.*;//java.utilクラスライブラリの利用を宣言する
//商品種類リストクラス
public class ItemTypeList {
private ArrayList itemTypeList;
//コンストラクタ
public ItemTypeList() {
itemTypeList = new ArrayList();
}
//リストに商品種類を追加する
public void add(ItemType newItemType){
itemTypeList.add(newItemType);
}
例題12-3
(ItemTypeList.java)
今まで作ってきたListクラス
はJavaAPIそっくりに作って
きたため、
変更点は3箇所のみ
12.3.4 JavaAPIドキュメント

Javaが提供する多くのクラスとそのAPI(メ
ソッドの書式など)をまとめたマニュアル


これを使えば知らない機能や知らないクラス
なども調べて使うことができます
メソッドの使い方を忘れてしまったり、知らない
機能を追加したいときはまずAPIを見てみる癖
をつけましょう
http://java.sun.com/j2se/1.3/ja/docs/ja/api/index.html