以前、Javaのデータ型は、基本データ型と参照データ型の大きく2つに分類される、と説明しました。 基本データ型には、整数型、実数型、論理型、文字型の4種類があり、整数型や実数型にも、いくつか種類がありました。
Javaでは、それぞれの基本データ型に対して、参照データ型が用意されています。 そのような参照データ型を、 ラッパー・クラス ( wrapper class )とよびます。
基本データ型とラッパー・クラスの対応は以下の通りです。 基本的に、基本データ型の先頭を大文字にするとラッパー・クラスになりますが、intとcharは違います。
種類 | 基本データ型 | ラッパー・クラス |
---|---|---|
整数型 | byte | Byte |
整数型 | short | Short |
整数型 | int | Integer |
整数型 | long | Long |
実数型 | float | Float |
実数型 | double | Double |
論理型 | boolean | Boolean |
文字型 | char | Character |
以下で説明する、リストやハッシュを利用するときは、基本データ型が使えず、参照データ型を使うことになっています。
なので、リストやハッシュで基本データ型を使いたかったら、代わりにラッパー・クラスを使うのです。
リストやハッシュのプログラムでは、
int
や
double
の代わりに、
Integer
や
Double
と書くということです。
以前、配列を説明したときに、配列は一度生成すると要素数は変えられない、と言いました。 どうしても要素数を変えたければ、大きめの配列の先頭部分を利用する、より大きな配列にコピーする、といった工夫が必要でした。 アレイ・リストというものを使うと、これらの工夫を自動的にやってくれます。
アレイ・リスト ( array list )とは、配列のようにデータを一列に格納でき、かつデータの追加や削除ができるデータ構造です。 ここでは、アレイ・リストを短く リスト ( list )とよびます。
リストの要素を リスト要素 ( list element )とよびます。 1つのリストの中で、リスト要素のデータ型はすべて同じ(これは配列も一緒)で、さらに、参照データ型でなくてはなりません。
まとめると、以下のようになります。
|
配列 | リスト |
---|---|---|
要素数 | 変えられない | 変えられる |
要素のデータ型 | なんでもよい | 参照データ型のみ |
以下はリストのプログラムの例です。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListTest { // リストのテスト /* 4*/ public static void main (String[] args) { /* 5*/ ArrayList<Integer> list = new ArrayList<Integer>(); // 宣言と生成 /* 6*/ list.add(10); // 追加 /* 7*/ list.add(11); // 追加 /* 8*/ list.add(12); // 追加 /* 9*/ list.add(13); // 追加 /* 10*/ list.add(14); // 追加 /* 11*/ System.out.println(list); // すべて出力 /* 12*/ } /* 13*/ }
[10, 11, 12, 13, 14] Completed with exit code: 0
プログラムでリストを扱うときは、先頭に
import java.util.*;
と書きます。
整数(int型)のリストのための変数を宣言するには、
int
を
Integer
に置き換え、
ArrayList<Integer> リスト名;
と書きます。
整数(int型)のリストを生成して変数に代入するには、
int
を
Integer
に置き換え、
リスト名 = new ArrayList<Integer>();
と書きます。 配列と違い、要素数は書きません。
なお、宣言と生成は、
ArrayList<Integer> リスト名 = new ArrayList<Integer>();
とまとめられます。
実数(double型)のリストの場合は、
double
を
Double
に置き換え、
ArrayList<Double> リスト名 = new ArrayList<Double>();
となります。
文字列のリストの場合は、文字列は参照データ型なので、
String
のまま
ArrayList<String> リスト名 = new ArrayList<String>();
です。
要素数を書かないということは、リストは最初、要素数0です。 要素数が0のリストを 空リスト ( empty list )とよびます。
リストに要素を追加するには、
リスト名.add(値);
と書きます。 これで、「リスト名」の最後に「値」が追加されます。 これを繰り返せば、複数の要素があるリストになります。
リストのすべての要素を確認するには、
System.out.println(リスト名);
と書きます。 これで、四角括弧に囲まれた要素の並びが出力されます。
リストに要素があれば、リスト要素に値を代入したり、リスト要素から値を取得したりできます。 ただし、プログラムの書き方は、配列と全然違います。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListSetGet { // リストに対する代入と取得 /* 4*/ public static void main (String[] args) { /* 5*/ ArrayList<Integer> list = new ArrayList<Integer>(); /* 6*/ list.add(100); // 追加 /* 7*/ list.add(101); // 追加 /* 8*/ list.set(1, 200); // 1番目に200を代入 /* 9*/ System.out.println(list.get(0)); // 0番目を取得 /* 10*/ System.out.println(list.get(1)); // 1番目を取得 /* 11*/ } /* 12*/ }
100 200 Completed with exit code: 0
「リスト名」の「添字」番目に「値」を代入するには、
リスト名.set(添字, 値);
と書きます。 「リスト名」の「添字」番目の値を取得するには、
リスト名.get(添字)
と書きます。
リストの要素数は、
リスト名.size()
で分かります。
以上をまとめ、配列と比較すると、以下のようになります。
|
配列 | リスト |
---|---|---|
値の追加 | (不可能) |
リスト名
.add(
値
);
|
値の代入 |
配列名
[
添字
] =
値
;
|
リスト名
.set(
添字
,
値
);
|
値の取得 |
配列名
[
添字
]
|
リスト名
.get(
添字
)
|
要素数 |
配列名
.length
|
リスト名
.size()
|
リストは生成された段階では空リストですが、必ずしも一行一行要素を追加するわけではありません。 例えば、要素数10のリストが必要であれば、for文で要素の追加を10回繰り返せばよいのです。
リストのすべての要素にアクセスするときも、for文を使います。
このとき、繰り返す回数は、リストの要素数である、リスト名
.size()
とします。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListLoop { // リストのループ /* 4*/ public static void main (String[] args) { /* 5*/ int i; /* 6*/ ArrayList<Integer> list = new ArrayList<Integer>(); /* 7*/ for (i = 0; i < 10; i++) { // 10回繰り返す /* 8*/ list.add(0); // 最後に0を追加 /* 9*/ } /* 10*/ for (i = 0; i < list.size(); i++) { // リストの要素数回繰り返す /* 11*/ System.out.println(list.get(i)); /* 12*/ } /* 13*/ } /* 14*/ }
0 0 0 0 0 0 0 0 0 0 Completed with exit code: 0
配列のときは、初期化ということを行うと、配列要素に一気に代入することができました。 リストでも、以下のようにすると初期化ができます。
ArrayList<Integer> リスト名 = new ArrayList<Integer>(Arrays.asList(値の並び));
つまり、リストの宣言・生成の括弧の中に
Arrays.asList()
を書き、その括弧の中に代入したい値をコンマで区切って並べるのです。
以下のプログラムでは、初期化を利用して要素数10のリストを生成しています。 行が長くなるので、値の並びで改行しています。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListInitialize { // リストの初期化 /* 4*/ public static void main (String[] args) { /* 5*/ ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( /* 6*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 /* 7*/ )); // リストの初期化 /* 8*/ System.out.println(list); /* 9*/ } /* 10*/ }
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29] Completed with exit code: 0
配列とリストの一番の違いは、リストは要素の追加や削除ができることです。
今までは、リストに要素を追加するとき、リスト名
.add(
値
);
としました。
これはリストの最後に「値」を追加するものです。
リストの「添字」番目に「値」を追加するには、
リスト名.add(添字, 値);
とします。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListAdd { // リストの要素の追加 /* 4*/ public static void main (String[] args) { /* 5*/ ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( /* 6*/ 10, 11, 12, 13, 14 /* 7*/ )); /* 8*/ list.add(1, 20); // 1番目に20を追加 /* 9*/ System.out.println(list); /* 10*/ } /* 11*/ }
[10, 20, 11, 12, 13, 14] Completed with exit code: 0
リストの「添字」番目を削除するには、
リスト名.remove(添字);
とします。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class ListRemove { // リストの要素の削除 /* 4*/ public static void main (String[] args) { /* 5*/ ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( /* 6*/ 10, 11, 12, 13, 14 /* 7*/ )); /* 8*/ list.remove(1); // 1番目を削除 /* 9*/ System.out.println(list); /* 10*/ } /* 11*/ }
[10, 12, 13, 14] Completed with exit code: 0
配列やリストは、要素を一列に並べたものですが、「添字と値の対応」と考えることもできます。 例えば、配列の初期化
int[] a = {10, 11, 12, 13, 14};
は、
int[] a; a[0] = 10; // 添字0と値10の対応 a[1] = 11; // 添字1と値11の対応 a[2] = 12; // 添字2と値12の対応 a[3] = 13; // 添字3と値13の対応 a[4] = 14; // 添字4と値14の対応
と同じですが、これを、添字0と値10の対応、添字1と値11の対応、…と考えるのです。
ハッシュ・マップ ( hash map )とは、配列やリストにおける「添字と値の対応」を、「キーと値の対応」に置き換えたデータ構造です。 ここでキーは、整数でも文字列でもよいです。
ハッシュ・マップを短く ハッシュ ( hash )とよんだり、 マップ ( map )とよんだりします。 ここでは、ハッシュとよぶことにします。
注意: 他のプログラミング言語では、ハッシュのことを、 連想配列 ( associative array )や 辞書 ( dictionary )などとよびます。
1つのハッシュの中で、キーのデータ型はすべて同じで、さらに、参照データ型でなくてはなりません。 値のデータ型もすべて同じで、参照データ型でなくてはなりません。 ただし、キーのデータ型と値のデータ型は、違ってもよいです。
配列やリストは、添字が要素の順番を表していました。 それに対して、ハッシュには添字がありませんので、順番もありません。
以下はハッシュのプログラムの例です。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class HashTest { // ハッシュのテスト /* 4*/ public static void main (String[] args) { /* 5*/ HashMap<String, Integer> hash = new HashMap<String, Integer>(); // 宣言と生成 /* 6*/ hash.put("tea", 150); // 追加 /* 7*/ hash.put("coffee", 120); // 追加 /* 8*/ hash.put("water", 100); // 追加 /* 9*/ System.out.println(hash); // すべて出力 /* 10*/ } /* 11*/ }
{tea=150, coffee=120, water=100} Completed with exit code: 0
プログラムでハッシュを扱うときは、先頭に
import java.util.*;
と書きます。
ハッシュのための変数を宣言するには、
HashMap<キーのデータ型, 値のデータ型> ハッシュ名;
と書きます。 ハッシュを生成して変数に代入するには、
ハッシュ名 = new HashMap<キーのデータ型, 値のデータ型>();
と書きます。
なお、宣言と生成は、
HashMap<キーのデータ型, 値のデータ型> ハッシュ名 = new HashMap<キーのデータ型, 値のデータ型>();
とまとめられます。
宣言・生成のときの、キーのデータ型や値のデータ型は、整数だったり文字列だったりします。
例えば、「teaの値段は120円です。」のように、商品名と値段の対応をハッシュにしたければ、文字列「tea」と整数「120」を対応させればよいので、
HashMap<String, Integer> hash = new HashMap<String, Integer>();
と宣言・生成します。
「1970年に大阪万博がありました。」のように、歴史年表をハッシュにしたければ、整数「1970」と文字列「大阪万博」を対応させればよいので、
HashMap<Integer, String> hash = new HashMap<Integer, String>();
と宣言・生成します。
「redの意味は赤です。」のように、英和辞典をハッシュにしたければ、文字列「red」と文字列「赤」を対応させればよいので、
HashMap<String, String> hash = new HashMap<String, String>();
と宣言・生成します。
ハッシュにキーと値の対応を追加するには、
ハッシュ名.put(キー, 値);
と書きます。 これで、「ハッシュ名」に「キー」と「値」の対応が追加されます。 これを繰り返せば、複数のキーと値の対応があるハッシュになります。
ハッシュのすべてのキーと値の対応を確認するには、
System.out.println(ハッシュ名);
と書きます。 これで、ブレース括弧に囲まれたキーと値の対応の並びが出力されます。
ハッシュにキーと値の対応があれば、キーを指定して、値を代入したり、値を取得したりできます。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class HashPutGet { // ハッシュに対する代入と取得 /* 4*/ public static void main (String[] args) { /* 5*/ HashMap<String, Integer> hash = new HashMap<String, Integer>(); /* 6*/ hash.put("milk", 250); // 追加 /* 7*/ hash.put("juice", 400); // 追加 /* 8*/ hash.put("juice", 380); // 代入 /* 9*/ System.out.println(hash.get("milk")); // 取得 /* 10*/ System.out.println(hash.get("juice")); // 取得 /* 11*/ System.out.println(hash.get("cocoa")); // 存在しない /* 12*/ } /* 13*/ }
250 380 null Completed with exit code: 0
「キー」に対応する「値」を代入するには、
ハッシュ名.put(キー, 値);
と書きます。
追加と代入が同じ
put()
ですが、キーに対応する値がなければ追加、あれば代入になります。
「キー」に対応する値を取得するには、
ハッシュ名.get(キー)
と書きます。 もし、「キー」に対応する値がなければnullという値になります。
「キー」に対応する値を削除するには、
ハッシュ名.remove(キー);
と書きます。
/* 1*/ import java.util.*; /* 2*/ /* 3*/ class HashRemove { // ハッシュからの削除 /* 4*/ public static void main (String[] args) { /* 5*/ HashMap<String, Integer> hash = new HashMap<String, Integer>(); /* 6*/ hash.put("milk", 250); // 追加 /* 7*/ hash.put("juice", 400); // 追加 /* 8*/ hash.remove("juice"); // 削除 /* 9*/ System.out.println(hash); /* 10*/ } /* 11*/ }
{milk=250} Completed with exit code: 0
リストの例として、プログラムの実行中に次々と文字列を入力し、それらを覚える、というものを考えます。 以前、配列を使ったときは、要素の追加ができないので、あらかじめ大きな配列を用意したりしました。 リストを使えば、要素の追加できるので、そのようなことをしなくてもよいのです。
データの終了の目印として、
end
と入力してもらうことにします。
文字列の比較は
==
ではなく
equals()
であることを思い出してください。
/* 1*/ import java.io.*; /* 2*/ import java.util.*; /* 3*/ /* 4*/ class ListInput { // リストへの入力 /* 5*/ public static void main (String[] args) throws IOException { /* 6*/ InputStreamReader isr = new InputStreamReader(System.in); /* 7*/ BufferedReader br = new BufferedReader(isr); /* 8*/ int i; /* 9*/ String input; /* 10*/ ArrayList<String> list = new ArrayList<String>(); // 文字列のリスト /* 11*/ System.out.println("終了はendを入力してください。"); /* 12*/ while (true) { // 無限ループ /* 13*/ System.out.print("文字列を入力してください: "); /* 14*/ input = br.readLine(); // データの入力 /* 15*/ if (input.equals("end")) { // データの終了 /* 16*/ break; /* 17*/ } /* 18*/ list.add(input); // データの追加 /* 19*/ } /* 20*/ for (i = 0; i < list.size(); i++) { // リストの要素数回繰り返す /* 21*/ System.out.println(list.get(i)); // データの取得 /* 22*/ } /* 23*/ } /* 24*/ }
終了はendを入力してください。 文字列を入力してください: red 文字列を入力してください: blue 文字列を入力してください: yellow 文字列を入力してください: end red blue yellow Completed with exit code: 0
ハッシュの使用例として、商品名を入力すると値段が表示されるプログラムを考えます。
プログラムでは、商品名と値段の対応をハッシュに追加してから、商品名を聞きます。
入力された商品名がハッシュになければ、値がnullになりますが、それを判定するには、値と
null
を
==
で比較します。
/* 1*/ import java.io.*; /* 2*/ import java.util.*; /* 3*/ /* 4*/ class HashAccess { // ハッシュへのアクセス /* 5*/ public static void main (String[] args) throws IOException { /* 6*/ InputStreamReader isr = new InputStreamReader(System.in); /* 7*/ BufferedReader br = new BufferedReader(isr); /* 8*/ String input; /* 9*/ Integer value; /* 10*/ HashMap<String, Integer> hash = new HashMap<String, Integer>(); /* 11*/ hash.put("tea", 150); // 追加 /* 12*/ hash.put("coffee", 120); // 追加 /* 13*/ hash.put("water", 100); // 追加 /* 14*/ System.out.print("商品名を入力してください: "); /* 15*/ input = br.readLine(); // データの入力 /* 16*/ value = hash.get(input); // 値の取得 /* 17*/ if (value == null) { // ハッシュになければ /* 18*/ System.out.println(input + "の値段は分かりません。"); /* 19*/ } else { /* 20*/ System.out.println(input + "の値段は" + value + "円です。"); /* 21*/ } /* 22*/ } /* 23*/ }
商品名を入力してください: tea teaの値段は150円です。 Completed with exit code: 0
商品名を入力してください: cider ciderの値段は分かりません。 Completed with exit code: 0
ハッシュを利用して、小さな英和辞典を作成してください。 まず、「red」と「赤」の対応、「blue」と「青」の対応、「yellow」と「黄色」の対応を、ハッシュに追加します。 そして英単語を入力してもらい、ハッシュにその英単語があれば意味を出力し、なければ分からないと出力します。
import java.io.*; import java.util.*; class SmallDictionary { public static void main (String[] args) throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); } }
英単語を入力してください: red redの意味は赤です。 Completed with exit code: 0
英単語を入力してください: green greenの意味は分かりません。 Completed with exit code: 0
余力のある人は、1回で終わるのではなく、 end と入力されるまで何度も繰り返すようにしてください。
終了はendを入力してください。 英単語を入力してください: red redの意味は赤です。 英単語を入力してください: green greenの意味は分かりません。 英単語を入力してください: end Completed with exit code: 0
今日の演習15の答案(Javaプログラム)をメールで提出してください。 差出人は大学発行のメール・アドレス(学生番号@cis.twcu.ac.jp)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(1月19日)を明記してください。
すべてのレポートの提出期限を、1月30日(火)とします。