以前、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つのリストの中で、リスト要素のデータ型はすべて同じ(これは配列も一緒)で、さらに、参照データ型でなくてはなりません。
まとめると、以下のようになります。
|
配列 | リスト |
---|---|---|
要素数 | 変えられない | 変えられる |
要素のデータ型 | なんでもよい | 参照データ型のみ |
以下はリストのプログラムの例です。
import java.util.ArrayList; class ListTest { // リストのテスト public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); // 宣言と生成 list.add(10); // 追加 list.add(11); // 追加 list.add(12); // 追加 list.add(13); // 追加 list.add(14); // 追加 System.out.println(list); // すべて出力 } }
PS ...\Desktop\java1> & ... 'ListTest' [10, 11, 12, 13, 14] PS ...\Desktop\java1>
プログラムでリストを扱うときは、先頭に
import java.util.ArrayList;
と書きます。
整数(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(リスト変数);
と書きます。 これで、四角括弧に囲まれた要素の並びが出力されます。
リストに要素があれば、リスト要素に値を代入したり、リスト要素から値を取得したりできます。 ただし、プログラムの書き方は、配列と全然違います。
import java.util.ArrayList; class ListSetGet { // リストに対する代入と取得 public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(100); // 追加 list.add(101); // 追加 list.set(1, 200); // 1番目に200を代入 System.out.println(list.get(0)); // 0番目を取得 System.out.println(list.get(1)); // 1番目を取得 } }
PS ...\Desktop\java1> & ... 'ListSetGet' 100 200 PS ...\Desktop\java1>
「リスト変数」の「添字」番目に「値」を代入するには、
リスト変数.set(添字, 値);
と書きます。 「リスト変数」の「添字」番目の値を取得するには、
リスト変数.get(添字)
と書きます。
リストの要素数は、
リスト変数.size()
で分かります。
以上をまとめ、配列と比較すると、以下のようになります。
|
配列 | リスト |
---|---|---|
値の追加 | (不可能) |
リスト変数
.add(
値
);
|
値の代入 |
配列変数
[
添字
] =
値
;
|
リスト変数
.set(
添字
,
値
);
|
値の取得 |
配列変数
[
添字
]
|
リスト変数
.get(
添字
)
|
要素数 |
配列変数
.length
|
リスト変数
.size()
|
リストは生成された段階では空リストですが、必ずしも一行一行要素を追加するわけではありません。 例えば、要素数10のリストが必要であれば、for文で要素の追加を10回繰り返せばよいのです。
リストのすべての要素にアクセスするときも、for文を使います。
このとき、繰り返す回数は、リストの要素数である、リスト変数
.size()
とします。
import java.util.ArrayList; class ListLoop { // リストのループ public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < 10; i++) { // 10回繰り返す list.add(0); // 最後に0を追加 } for (int i = 0; i < list.size(); i++) { // リストの要素数回繰り返す System.out.println(list.get(i)); } } }
PS ...\Desktop\java1> & ... 'ListLoop' 0 0 0 0 0 0 0 0 0 0 PS ...\Desktop\java1>
配列のときは、初期化ということを行うと、配列要素に一気に代入することができました。 リストでも、以下のようにすると初期化ができます。
ArrayList<Integer> リスト変数 = new ArrayList<Integer>(Arrays.asList(値の並び));
つまり、リストの宣言・生成の括弧の中に
Arrays.asList()
を書き、その括弧の中に代入したい値をコンマで区切って並べるのです。
ただし、プログラムの先頭に
import java.util.Arrays;
を追加します。
以下のプログラムでは、初期化を利用して要素数10のリストを生成しています。 行が長くなるので、値の並びで改行しています。
import java.util.ArrayList; import java.util.Arrays; class ListInitialize { // リストの初期化 public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 )); // リストの初期化 System.out.println(list); } }
PS ...\Desktop\java1> & ... 'ListInitialize' [20, 21, 22, 23, 24, 25, 26, 27, 28, 29] PS ...\Desktop\java1>
配列とリストの一番の違いは、リストは要素の追加や削除ができることです。
今までは、リストに要素を追加するとき、リスト変数
.add(
値
);
としました。
これはリストの最後に「値」を追加するものです。
リストの「添字」番目に「値」を追加するには、
リスト変数.add(添字, 値);
とします。
import java.util.ArrayList; import java.util.Arrays; class ListAdd { // リストの要素の追加 public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( 10, 11, 12, 13, 14 )); list.add(1, 20); // 1番目に20を追加 System.out.println(list); } }
PS ...\Desktop\java1> & ... 'ListAdd' [10, 20, 11, 12, 13, 14] PS ...\Desktop\java1>
リストの「添字」番目を削除するには、
リスト変数.remove(添字);
とします。
import java.util.ArrayList; import java.util.Arrays; class ListRemove { // リストの要素の削除 public static void main (String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList( 10, 11, 12, 13, 14 )); list.remove(1); // 1番目を削除 System.out.println(list); } }
PS ...\Desktop\java1> & ... 'ListRemove' [10, 12, 13, 14] PS ...\Desktop\java1>
配列やリストは、要素を一列に並べたものですが、「添字と値の対応」と考えることもできます。 例えば、配列の初期化
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つのハッシュの中で、キーのデータ型はすべて同じで、さらに、参照データ型でなくてはなりません。 値のデータ型もすべて同じで、参照データ型でなくてはなりません。 ただし、キーのデータ型と値のデータ型は、違ってもよいです。
配列やリストは、添字が要素の順番を表していました。 それに対して、ハッシュには添字がありませんので、順番もありません。
以下はハッシュのプログラムの例です。
import java.util.HashMap; class HashTest { // ハッシュのテスト public static void main (String[] args) { HashMap<String, Integer> hash = new HashMap<String, Integer>(); // 宣言と生成 hash.put("tea", 150); // 追加 hash.put("coffee", 120); // 追加 hash.put("water", 100); // 追加 System.out.println(hash); // すべて出力 } }
PS ...\Desktop\java1> & ... 'HashTest' {tea=150, coffee=120, water=100} PS ...\Desktop\java1>
プログラムでハッシュを扱うときは、先頭に
import java.util.HashMap;
と書きます。
ハッシュのための変数を宣言するには、
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(ハッシュ変数);
と書きます。 これで、ブレース括弧に囲まれたキーと値の対応の並びが出力されます。
ハッシュにキーと値の対応があれば、キーを指定して、値を代入したり、値を取得したりできます。
import java.util.HashMap; class HashPutGet { // ハッシュに対する代入と取得 public static void main (String[] args) { HashMap<String, Integer> hash = new HashMap<String, Integer>(); hash.put("milk", 250); // 追加 hash.put("juice", 400); // 追加 hash.put("juice", 380); // 代入 System.out.println(hash.get("milk")); // 取得 System.out.println(hash.get("juice")); // 取得 System.out.println(hash.get("cocoa")); // 存在しない } }
PS ...\Desktop\java1> & ... 'HashPutGet' 250 380 null PS ...\Desktop\java1>
「キー」に対応する「値」を代入するには、
ハッシュ変数.put(キー, 値);
と書きます。
追加と代入が同じ
put()
ですが、キーに対応する値がなければ追加、あれば代入になります。
「キー」に対応する値を取得するには、
ハッシュ変数.get(キー)
と書きます。 もし、「キー」に対応する値がなければnullという値になります。
「キー」に対応する値を削除するには、
ハッシュ変数.remove(キー);
と書きます。
import java.util.HashMap; class HashRemove { // ハッシュからの削除 public static void main (String[] args) { HashMap<String, Integer> hash = new HashMap<String, Integer>(); hash.put("milk", 250); // 追加 hash.put("juice", 400); // 追加 hash.remove("juice"); // 削除 System.out.println(hash); } }
PS ...\Desktop\java1> & ... 'HashRemove' {milk=250} PS ...\Desktop\java1>
リストの例として、プログラムの実行中に次々と文字列を入力し、それらを覚える、というものを考えます。 以前、配列を使ったときは、要素の追加ができないので、あらかじめ大きな配列を用意したりしました。 リストを使えば、要素の追加できるので、そのようなことをしなくてもよいのです。
データの終了の目印として、
end
と入力してもらうことにします。
文字列の比較は
==
ではなく
equals()
であることを思い出してください。
import java.util.ArrayList; import java.util.Scanner; class ListInput { // リストへの入力 public static void main (String[] args) { Scanner stdIn = new Scanner(System.in); String input; ArrayList<String> list = new ArrayList<String>(); // 文字列のリスト System.out.println("終了はendを入力してください。"); while (true) { // 無限ループ System.out.print("文字列を入力してください: "); input = stdIn.nextLine(); // データの入力 if (input.equals("end")) { // データの終了 break; } list.add(input); // データの追加 } for (int i = 0; i < list.size(); i++) { // リストの要素数回繰り返す System.out.println(list.get(i)); // データの取得 } } }
PS ...\Desktop\java1> & ... 'ListInput' 終了はendを入力してください。 文字列を入力してください: red 文字列を入力してください: blue 文字列を入力してください: yellow 文字列を入力してください: end red blue yellow PS ...\Desktop\java1>
ハッシュの使用例として、商品名を入力すると値段が表示されるプログラムを考えます。
プログラムでは、商品名と値段の対応をハッシュに追加してから、商品名を聞きます。
入力された商品名がハッシュになければ、値がnullになりますが、それを判定するには、値と
null
を
==
で比較します。
import java.util.HashMap; import java.util.Scanner; class HashAccess { // ハッシュへのアクセス public static void main (String[] args) { Scanner stdIn = new Scanner(System.in); String input; Integer value; HashMap<String, Integer> hash = new HashMap<String, Integer>(); hash.put("tea", 150); // 追加 hash.put("coffee", 120); // 追加 hash.put("water", 100); // 追加 System.out.print("商品名を入力してください: "); input = stdIn.nextLine(); // データの入力 value = hash.get(input); // 値の取得 if (value == null) { // ハッシュになければ System.out.println(input + "の値段は分かりません。"); } else { System.out.println(input + "の値段は" + value + "円です。"); } } }
PS ...\Desktop\java1> & ... 'HashAccess' 商品名を入力してください: tea teaの値段は150円です。 PS ...\Desktop\java1>
PS ...\Desktop\java1> & ... 'HashAccess' 商品名を入力してください: cider ciderの値段は分かりません。 PS ...\Desktop\java1>
ハッシュを利用して、小さな英和辞典を作成してください。 まず、「red」と「赤」の対応、「blue」と「青」の対応、「yellow」と「黄色」の対応を、ハッシュに追加します。 そして英単語を入力してもらい、ハッシュにその英単語があれば意味を出力し、なければ分からないと出力します。
import java.util.HashMap; import java.util.Scanner; class SmallDictionary { public static void main (String[] args) { Scanner stdIn = new Scanner(System.in); } }
PS ...\Desktop\java1> & ... 'SmallDictionary' 英単語を入力してください: red redの意味は赤です。 PS ...\Desktop\java1>
PS ...\Desktop\java1> & ... 'SmallDictionary' 英単語を入力してください: green greenの意味は分かりません。 PS ...\Desktop\java1>
余力のある人は、1回で終わるのではなく、 end と入力されるまで何度も繰り返すようにしてください。
PS ...\Desktop\java1> & ... 'SmallDictionary2' 終了はendを入力してください。 英単語を入力してください: red redの意味は赤です。 英単語を入力してください: green greenの意味は分かりません。 英単語を入力してください: end PS ...\Desktop\java1>
今日の演習15の答案(Javaプログラム)をメールで提出してください。 差出人は大学発行のメール・アドレス(学生番号@cis.twcu.ac.jp)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(7月18日)を明記してください。
すべてのレポートの提出期限を2025年8月1日(金)とします。