Javaプログラミング入門【第7回】

1,538 views
1,394 views

Published on

ガーベッジコレクション
コレクション

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,538
On SlideShare
0
From Embeds
0
Number of Embeds
61
Actions
Shares
0
Downloads
10
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Javaプログラミング入門【第7回】

  1. 1. Javaプログラミング入門 第7回
  2. 2. 今日の講義 • ガーベッジコレクション • コレクション
  3. 3. インスタンスの生成と参照 • 新しいインスタンスを生成する Hoge obj = new Hoge(); • Hogeクラスのインスタンスが1つ作り、変数obj を初期化している • 変数objが持っているものは?
  4. 4. 変数はインスタンスを参照している • 変数objはHogeクラスのインスタンスの場所(ア ドレス)の情報を持っている 変数obj objにはHogeクラスの インスタンスのアドレスを 持っている Hogeクラスの インスタンスそのもの ヒープ
  5. 5. つまり? 1. new Hoge()で、Hogeクラスのインスタンスの 領域を確保する 2. Hoge obj = new Hoge(); で変数objに作った インスタンスの場所を教えている
  6. 6. 変数はインスタンスを参照する • 次の処理は何を意味するのか? Hoge obj1 = new Hoge(); Hoge obj2 = obj1;
  7. 7. obj1を介してインスタンスを変更する と? 変数obj1 変数obj2 Hogeクラスの インスタンスそのもの ヒープ
  8. 8. インスタンスの参照をやめる • 次の処理は何を意味するか? Hoge obj1 = new Hoge(); Hoge obj2 = obj1; obj1 = null;
  9. 9. obj1を介してインスタンスを変更する と? 変数obj1 null 変数obj2 代入 null 参照が なくなる Hogeクラスの インスタンスそのもの ヒープ
  10. 10. 誰からも参照されていないインスタン ス • 次の処理は何を意味するか? Hoge obj1 = new Hoge(); Hoge obj2 = obj1; obj1 = null; obj2 = null;
  11. 11. 誰から参照されなくなるとゴミになる 変数obj1 null 変数obj2 null 代入 null 参照が なくなる Hogeクラスの インスタンス ガーベッジ ヒープ
  12. 12. 引数として渡されるインスタンス • 変数objを引数にしてメソッド呼び出しを行う Hoge obj = new Hoge(); methodHoge(obj); • メソッドmethodHogeに渡されたのは、objイン スタンスのアドレス
  13. 13. ガーベッジコレクタ(ガーベッジコレク ションを行う仕組み) • newを使ってインスタンスをどんどん作ってい くと、その度にメモリが消費されていく →いつかはメモリが足りなくなる →インスタンスが作れなくなる • Java仮想マシンが「ガーベッジコレクション」 を開始する →誰からも参照されていないインスタンス (ガーベッジ)が占めているメモリを解放し、その メモリ領域を再利用する
  14. 14. ガーベッジコレクションの動作確認 • 残りのメモリ量を表示しながら、ガーベッジとなるイン スタンスを生成し続けるプログラム public class GcTest1 { public static void main(String[] args) { while(true) { String s = new String("123456789"); System.out.println("残メモリ : " + Runtime.getRuntime().freeMemory()); } } }
  15. 15. 実行すると 残りメモリが減っていく ↓ 残りメモリが増える ↓ 残りメモリが減っていく を繰り返していく • 本当にメモリが不足している場合は、 OutOfMemoryErrorというエラーがスローされ る
  16. 16. メモリ管理に関するメソッド メソッド 処理 public long freeMemory() 利用可能なメモリの大きさをバイト単位 で得る public long totalMemory() 全メモリの大きさをバイト単位で得る public long maxMemory() 最大メモリの大きさをバイト単位で得る public void gc() ガーベッジコレクタを動作させる public static Runtime getRuntime() 現在のRuntimeインスタンスを得る
  17. 17. 配列の場合 • ヒープ上のメモリは、クラスインスタンスだけではなく、配 列を確保する場合も消費する public class GcTest2 { public static void main(String[] args) { while(true) { int[] a = new int[100]; for (int i = 0; i < a.length; i++) { a[i] = i; } System.out.println("残メモリ : " + Runtime.getRuntime().freeMemory()); } } }
  18. 18. メモリが回収されないプログラム public class GcTest3 { static ArrayList<int[]> list = new ArrayList<int[]>(); public static void main(String[] args) { while(true) { int[] a = new int[1000]; for (int i = 0; i < a.length; i++) { a[i] = i; } list.add(a); System.out.println("残メモリ : " + Runtime.getRuntime().freeMemory()); } } }
  19. 19. ガーベッジにならないインスタンス • whileの中で、毎回配列を生成しているが、可変 長配列ArrayListに追加している • 配列はArrayListから常に参照されるため、ガー ベッジ(ごみ)にならない
  20. 20. プログラム内で強制的にガーベッジコ レクションを行う public class GcTest4 { public static void main(String[] args) { for (int n = 0; true; n++) { int[] a = new int[1000]; for (int i = 0; i < a.length; i++) { a[i] = i; } if (n % 100 == 0) { System.out.println("gcを呼び出します"); System.gc(); } System.out.println("残メモリ : " + Runtime.getRuntime().freeMemory()); } } }
  21. 21. finalizeメソッド • 参照されなくなったインスタンスがガーベッジコレ クションによって回収・再利用される前に、そのイ ンスタンスのfinalizeメソッドが呼び出される • finalizeメソッドが呼び出されるのは、ガーベッジに なった瞬間ではなく、「ガーベッジになったインス タンスの領域が再利用される前のどこか」 • メモリ消費量によって呼ばれたり、呼ばれる順序が 確定しているわけではない • 使用している資源(リソース)を明示的に解放するに は、closeやdispose、destoryメソッドを使用する
  22. 22. 演習1 • 次のプログラムを動かした時、※印のち天で生 き残っているClassAとClassBのインスタンスは どれか?「トム」「ピーター」というふうに、 その名前で答えよ。 注)クラスは3クラスある
  23. 23. ClassA.java public class ClassA { public static ClassA last = null; public String name; public ClassA(String name) { this.name = name; last = this; } @Override public String toString() { return "[" + name + "]"; } }
  24. 24. ClassB.java public class ClassB extends ClassA { public ClassA friend; public ClassB(String name) { super(name); } public ClassB(String name, ClassA friend) { super(name); this.friend = friend; } @Override public String toString() { return "[" + name + ", " + friend + "]"; } }
  25. 25. GcQuiz.java(その1) public class GcQuiz { public static ClassA q = new ClassA("ジマイマ"); public ClassA r = new ClassA("レベッカ"); public static void main(String[] args) { ClassA a = new ClassA("マトン"); ClassA b = new ClassA("トム"); ClassA c = new ClassA("パペット"); ClassB[] arrayA = new ClassB[4]; b = c; for (int i = 0; i < arrayA.length; i++) { arrayA[i] = new ClassB("犬" + i); } arrayA[3].friend = arrayA[3]; arrayA[0] = arrayA[1]; c = arrayA[2]; arrayA[1] = null; ClassA d = arrayA[0];
  26. 26. GcQuiz.java(その2 続き) ClassB arrayB[] = new ClassB[4]; arrayB[0] = new ClassB("フロプシー", new ClassA("ネズミ ")); arrayB[1] = new ClassB("モプシー", new ClassA("アナキン ")); arrayB[2] = new ClassB("サテンドール", c); arrayB[3] = new ClassB("ピーター", new ClassA("ベンジャミ ン")); } } arrayA = null; arrayB[0].friend = null; arrayB[1] = null; arrayB[2] = null; ClassB e = new ClassB("ルーシー", new ClassA("ティギー")); e = null; // ※ここの時点で参照されているインスタンスは何か?
  27. 27. コレクションとは • 「たくさんのインスタンスを管理する」という目的 を持ったクラスやインターフェースの総称 • Javaのコレクションは主にjava.utilというパッケー ジに集められており、クラスやインターフェースが 連携して便利な機能を提供している utilはutilityの略で、「便利な道具類」という意 味 • クラスやインターフェースが連携していることを強 調するために、コレクションのことをJavaコレク ションフレームワーク(Java Collections Framework) と呼ぶこともある
  28. 28. 配列の復習 public class ArrayTest { public static void main(String[] args) { // 配列の確保 String[] array = new String[3]; // 要素の代入 array[0] = "Alice"; array[1] = "Bob"; array[2] = "Chris"; } } // 要素の参照 for (int i = 0; i < array.length; i++) { System.out.println(array[i]); }
  29. 29. 配列arrayの様子 array 配列の長さ array.length array[0] array[1] array[2] Alice Bob Chris
  30. 30. 配列の長さは固定 • 配列の長さは3なので、有効な添字は0,1,2の 3種類。 array[3]に代入/参照しようとすると、添字が範 囲外なので例外 (ArrayIndexOutOfBoundsException)が発生する。 • javaでは配列を確保したあとで、配列の長さを 伸ばすことは出来ない
  31. 31. 自動的に長くなるArrayList • 通常の配列は長さが固定だが、ArrayListはメ モリがなくならない限り何個でも要素が追加で き、要素が追加される度にサイズ(長さ)が自動 的に長くなる • たくさんのインスタンスを入れる「入れ物」の 役割を果たすクラスのことを、コンテナ (container)、もしくはコンテナクラスと呼ぶ
  32. 32. ArrayListを使ってみる import java.util.ArrayList; public class ArrayListTest1 { public static void main(String[] args) { // ArrayListインスタンスの確保 ArrayList<String> list = new ArrayList<String>(); // 要素の追加(addメソッド) list.add("Alice"); list.add("Bob"); list.add("Chris"); // 要素の参照(getメソッド) for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } }
  33. 33. ArrayListの宣言 • java.util.ArrayListをimportすることにより、 ArrayListクラスを使うことが出来る • ArrayList<String> list = new ArrayList<String>(); ▫ ArrayList<String>型の変数listを宣言 ▫ ArrayList<String>のインスタンスを1つ確保 ▫ そのインスタンスで変数listを初期化
  34. 34. パラメータ付き型とジェネリクス • ArrayListの後の<String> ▫ 要素がString型のArrayList型を意味 • ArrayList<String>のような型のことを、パラ メータ付き型、<>でくくられたStringの部分を 型パラメータと言う • 型パラメータを使って型の宣言が出来る機能の ことをジェネリクスと言う
  35. 35. ArrayListのインスタンスの確保 • 新しい配列を確保する場合は new String[3] のように、要素の個数(配列の長さ)を指定する必 要があるが、ArrayListのインスタンスを確保する 場合は、要素の個数は指定しない ▫ 格納出来る要素の個数に制限がないため
  36. 36. 要素の追加(addメソッド) • ArrayListのインスタンスに要素を追加する場合 はaddメソッドを使用する • list.add("Alice"); という文を実行すると、 ArrayListの最後に"Alice"というStringのインス タンスが追加される ▫ "Alice"という要素が既にArrayListの中にあったと しても、新たに追加される(重複を許可する) • 要素の代入はsetメソッドを使用する list.set(0, "Riddle");
  37. 37. 要素数(sizeメソッド) • ArrayListのインスタンスが、現在何個の要素を 持っているかを調べるにはsizeメソッドを使用 する
  38. 38. 参照(getメソッド) • ArrayList内の位置(添字)を指定して要素を参照 するには、getメソッドを使用する • もしも、list.get(i)のiの値が範囲外(0より小さい か、sizeメソッドの戻り値以上)の場合は、 IndexountOfBoundsExceptionが発生する
  39. 39. 配列とArrayListの比較 配列 java.util.ArrayList 確保 array = new 要素の型[要 素数]; list = new ArrayList<要素の型 >(); 代入(置き換え) array[添字] = 要素; list.set(添字, 要素); 追加 なし list.add(要素); 参照 array[添字] list.get(添字); 要素数 array.length list.size(); 添字が範囲外の時 ArrayIndexoutOfBoundsE xception IndexOutOfBoundsException
  40. 40. ArrayListのイメージ図 list 要素の個数 list.size() list.add(追加要素) list.get(0) list.get(1) list.get(2) 追加すると自動的に伸びる ArrayListのインスタンス Alice Bob Chris
  41. 41. イテレータ • ArrayListでi番目の要素を参照するには、list.get(i) という式を使用する • しかし、Javaのコレクションフレームワークで提供 されているコンテナクラスの中には、「i番目の要 素」を得る手段がなかったり、「i番目の要素」を 得るために時間がかかったりする • すべての要素を参照する手段として、イテレータ (iterator)と呼ばれる機能がある。 ▫ イテレート(iterate)は「反復する」「繰り返す」 • イテレータの機能はjava.util.Iteratorインター フェースで実現されている
  42. 42. イテレータを使ってみる import java.util.ArrayList; import java.util.Iterator; public class IteratorTest { public static void main(String[] args) { // ArrayListインスタンスの確保 ArrayList<String> list = new ArrayList<String>(); // 要素の追加(addメソッド) list.add("Alice"); list.add("Bob"); list.add("Chris"); // イテレータを使ったforループ for (Iterator<String> it = list.iterator(); it.hasNext();) { String name = it.next(); System.out.println(name); } } }
  43. 43. iteratorメソッド • for文の中の Iterator<String> it = list.iterator(); iteratorメソッドを使用して、ArrayListのインスタンスか らイテレータを得ている。 変数itがiteratorメソッドの戻り値(イテレータ)で初期化さ れている。イテレータは、「本を読んでいる時の現在の ページに挟んでいるしおり」と似たような働きをする • for文の条件式は it.hasNext(); イテレータに対して「次の要素はあるか?」と尋ねる。戻 り値はboolean。次の要素がある場合は、trueが返却され、 ない場合は、falseが返却される
  44. 44. 拡張forループ • イテレータを使ったforループを簡単に書くこと ができる拡張forループという構文がJavaでは用 意されている。 • この構文を使うと、添字もイテレータもプログ ラム内に書く必要がなくなる
  45. 45. 拡張for文を使ってみる import java.util.ArrayList; public class EnhancedForLoopTest { public static void main(String[] args) { // ArrayListインスタンスの確保 ArrayList<String> list = new ArrayList<String>(); // 要素の追加(addメソッド) list.add("Alice"); list.add("Bob"); list.add("Chris"); // 拡張forループ for (String name : list) { System.out.println(name); } } }
  46. 46. 拡張for文 • 以下の部分が拡張for文 for (String name : list) { System.out.println(name); } • 構文 for (要素の型 変数名: コレクションの式) { 変数を使った処理 } • 拡張for文を使うことによって、イテレータを得る iteratorメソッドやイテレータを次の要素があるかどう かを調べるhasNextメソッドも、nextメソッドも書かず に済む。 • 配列でも拡張for文を記述することが出来る
  47. 47. プリミティブ型のコレクション • ArrayList<String>は「要素がString型の ArrayList型」を意味する • ただし、<>の中の型はプリミティブ型(基本型) を型パラメータとして書くことは出来ない • 「要素がint型のArrayList型」を作る場合はint 型のラッパークラスIntegerクラスを使う必要が ある ▫ ☓ ArrayList<int> ▫ ○ ArrayList<Integer>
  48. 48. intをArrayListで管理する import java.util.ArrayList; public class IntegerArrayListTest { public static void main(String[] args) { // ArrayListのインスタンスの確保 ArrayList<Integer> list = new ArrayList<Integer>(); // 要素の追加 list.add(12); list.add(34); list.add(56); list.add(78); // 拡張forループ for (int n : list) { System.out.println(n); } } }
  49. 49. プリミティブ型とラッパークラスの自 動変換 • プリミティブ型(int)とそのラッパークラス (Integer)クラスの間では自動的な変換が行われ ている ▫ list.add(12); int→Integerの変換 ▫ 拡張for文ではInteger→intの変換 for (int n : list) { .... }
  50. 50. オートボクシング • プリミティブ型→ラッパークラスへの変換 ▫ ボクシング(boxing conversion) • ラッパークラス→プリミティブ型への変換 ▫ アンボクシング(unboxing conversion) • 自動的にボクシング、アンボクシングが行われ ることを、オートボクシング(autoboxing)、 オートアンボクシング(autounboxing)と言う ▫ プリミティブ型をラッパークラスで包む様子を 「ボックス(箱)に入れること」に見立てている
  51. 51. ラッパークラスの例 プリミティブ型 ラッパークラス boolean Boolean byte Byte char Character double Double float Float int Integer long Long short Short
  52. 52. 削除と確認 • ArrayListに対する操作は、追加、代入、参照だ けではなく、要素の削除(remove)や、特定の要 素を含んでいるか(contains)を調べることが出来 る
  53. 53. 削除と確認の例(続く) public class RemoveContains { public static void main(String[] args) { // ArrayListインスタンスの確保 ArrayList<String> list = new ArrayList<String>(); // 要素の追加(addメソッド) list.add("Alice"); list.add("Bob"); list.add("Chris"); list.add("Diana"); list.add("Elmo"); // 削除の前に要素を表示 System.out.println("削除の前"); for (int i = 0; i < list.size(); i++) { System.out.println(i + ":" + list.get(i)); } System.out.println();
  54. 54. 削除と確認の例(続き) // AliceとBobとElmoを削除 list.remove("Alice"); list.remove("Bob"); list.remove("Elmo"); // 削除の後に要素を表示 System.out.println("削除の後"); for (int i = 0; i < list.size(); i++) { System.out.println(i + ":" + list.get(i)); } System.out.println(); // Aliceは含まれているか? if (list.contains("Alice")) { System.out.println("listにAliceは含まれる"); } else { System.out.println("listにAliceは含まれていない"); } } }
  55. 55. 要素の移動 • AliceとBobを削除した後、Chrisの位置は0に なった • removeメソッドで要素を削除すると、残った要 素は前の方に移動することに注意する
  56. 56. Javaコレクションフレームワークの全 体像(抜粋) AbstractSequential List<E> LinkedList<E> AbstractList<E> ArrayList<E> AbstractCollection< E> AbstractQueue<E> EnumSet<E extends Enum<E>> AbstractSet<E> HashSet<E> ConcurrentHashMa p<K, V> TreeSet<E> java.lang.Object AbstractMap<K, V> EnumMap<E extends Enum<K>, V> HashMap<K, V> Dictionary<K, V> LinkedHashMap<K, V> Hashtable<K, V> Properties LinkedHashSet<E>
  57. 57. List<E> • 「要素が並んでいるリスト」を管理するイン ターフェース • <E>は型パラメータを表す • データをある順序で並べたり、並んだ順序に 従って処理を行ったりするときに使うのがList • 代表的なクラス:ArrayList
  58. 58. Queue<E> • 「キュー」を管理するインターフェース • リストの一種とみなすことができるが、プログラム でよく使われるデータ構造なので、キュー専用のメ ソッドが用意されている • 代表的なクラス:java.util.concurrentパッケージの ConcurrentLinkedQueueクラス ▫ 2つのスレッドでデータの受け渡しを行うことが出来 る • LinkedListはListインターフェースとQueueイン ターフェースも実装しているので、キューとして用 いることができる
  59. 59. キューとスタック • キューとは「先入れ先だし(First-In-First-Out, FIFO)」を表すデータ構造 • スタックとは「後入れ先出し(Last-In-First-Out, LIFO)」を表すデータ構造
  60. 60. キューやスタックの実装 • LinkedList ▫ 要素の挿入や削除を高速に行うことが出来るクラ ス ▫ 頻繁に要素を挿入・削除する場合に使う ▫ 要素の挿入にはaddメソッド、削除にはremoveメ ソッドを使用する ▫ ※LinkedListの挿入・削除は高速だが、「先頭か ら何番目」のように「指定した位置にある要素を 参照」する処理には低速。先頭からの位置を指定 して要素を参照する場合には、ArrayListを使った 方がよい
  61. 61. LinkedListを使った例 import java.util.LinkedList; public class LinkedListTest { public static void main(String[] args) { // LinkedListのインスタンスを確保する LinkedList<String> list = new LinkedList<String>(); // 要素の追加(addメソッド) list.add("Bob"); list.add("Chris"); list.add("Diana"); list.add("Elmo"); // 現在の状態 System.out.println(list); // 先頭にAliceを挿入 list.addFirst("Alice"); // Aliceを挿入した後の状態 System.out.println(list); } }
  62. 62. LinkedListをキューとして用いる • LinkedListはListインターフェースだけではなく、 Queueインターフェースも実装しているので、 キューとして用いることも出来る。 • キューとして用いる場合は Queue<String> queue = new LinkedList<String>(); として宣言する方が意図がはっきりする ▫ キューへ要素を追加する場合は、offerまたはaddメ ソッド ▫ キューの先頭の要素を参照する場合は、peekまたは elementメソッド ▫ キューの先頭から要素を取り出すときには、pollまた はremoveメソッド
  63. 63. Queueインターフェースのメソッド 失敗を戻り値で表現す る 失敗を例外で表現する 先頭の要素を参照する peek キューが空の時null element キューが空の時 NoSuchElementException 先頭から要素を取り出 す poll キューが空の時null remove キューが空の時 NoSuchElementException 末尾に要素を追加する offer 容量不足の時false add 容量不足の時 IllegalStateException
  64. 64. LinkedListをキューとして用いた例 (offer,peek,poll) import java.util.LinkedList; import java.util.Queue; public class LinkedListTest2 { public static void main(String[] args) { // QueueとしてLinkedListのインスタンスを確保する Queue<String> queue = new LinkedList<String>(); // 要素の追加 queue.offer("Alice"); System.out.println("offerの後のqueue = " + queue); queue.offer("Bob"); System.out.println("offerの後のqueue = " + queue); queue.offer("Chris"); System.out.println("offerの後のqueue = " + queue); queue.offer("Diana"); System.out.println("offerの後のqueue = " + queue); // 先頭要素の参照 while (queue.peek() != null) { // 要素の抽出と削除 String name = queue.poll(); System.out.println("pollの戻り値 = " + name); System.out.println("pollの後のqueue = " + queue); } } }
  65. 65. LinkedListをキューとして用いた例 (add,element,remove) ※続く import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.Queue; public class LinkedListTest3 { public static void main(String[] args) { // QueueとしてLinkedListのインスタンスを確保する Queue<String> queue = new LinkedList<String>(); // 要素の追加 queue.add("Alice"); System.out.println("addの後のqueue = " + queue); queue.add("Bob"); System.out.println("addの後のqueue = " + queue); queue.add("Chris"); System.out.println("addの後のqueue = " + queue); queue.add("Diana"); System.out.println("addの後のqueue = " + queue);
  66. 66. LinkedListをキューとして用いた例 (add,element,remove) ※続き try { while (true) { // 先頭要素の参照 String name = queue.element(); System.out.println("elementの戻り値 = " + name); // 要素の抽出と削除 name = queue.remove(); System.out.println("removeの戻り値 = " + name); System.out.println("removeの後のqueue = " + queue); } } catch (NoSuchElementException e) { e.printStackTrace(); } } }
  67. 67. LinkedListをスタックとして用いる(続 く) import java.util.LinkedList; import java.util.NoSuchElementException; public class LinkedListTest4 { public static void main(String[] args) { // StackとしてLinkedListのインスタンスを確保する LinkedList<String> stack = new LinkedList<String>(); // 要素の追加 stack.addFirst("Alice"); System.out.println("addの後のqueue = " + stack); stack.addFirst("Bob"); System.out.println("addの後のqueue = " + stack); stack.addFirst("Chris"); System.out.println("addの後のqueue = " + stack); stack.addFirst("Diana"); System.out.println("addの後のqueue = " + stack); stack.addFirst("Elmo"); System.out.println("addの後のqueue = " + stack);
  68. 68. LinkedListをスタックとして用いる(続 き) try { while (true) { // 先頭要素の参照 String name = stack.getFirst(); System.out.println("getFirstの戻り値 = " + name); // 要素の抽出と削除 name = stack.removeFirst(); System.out.println("removeFirstの戻り値 = " + name); System.out.println("removeFirstの後のqueue = " + stack); } } catch (NoSuchElementException e) { e.printStackTrace(); } } }
  69. 69. Set<E> • 「要素の集合」を管理するインターフェース • Setインターフェースで管理する集合は、同一の 要素を複数個追加することはできない • 代表的なクラス:HashSet
  70. 70. Map<K,V> • 「キーと値の対応関係」を管理するインター フェース • 型パラメータのKはキー(key)の型を、Vは値 (value)の型を表す • あるキーに対して特定の値が対応するので、 Mapインターフェースを使うときには同一の キーを複数個登録することは出来ない • 代表的なクラス:HashMap
  71. 71. キーと値の対応関係 • HashMapはキーと値の対応関係を表すクラス • キーとしてString、値をIntegerを指定する場合 は次のようになる ▫ HashMap<String, Integer> • HashMap<String, Integer>には、「Stringのイ ンスタンスをキーとし、Integerのインスタンス を値としたペア」を複数個追加出来るが、キー には重複があってはいけない
  72. 72. 名前と年齢をMapを使って表現する例 (続く) import java.util.HashMap; import java.util.Map; public class HashMapTest { public static void main(String[] args) { // MapとしてHashMapのインスタンスを確保する Map<String, Integer> map = new HashMap<String, Integer>(); // キーと値のペアを追加 map.put("Alice", 18); map.put("Bob", 30); map.put("Chris", 47); map.put("Diana", 25); map.put("Elmo", 6);
  73. 73. 名前と年齢をMapを使って表現する例 (続く) // エントリに関する拡張forループ for (Map.Entry<String, Integer> entry: map.entrySet()) { System.out.println(entry.getKey() + " => " + entry.getValue()); } System.out.println(); // キーに関する拡張forループ for (String name : map.keySet()) { System.out.println(name); } System.out.println(); // 値に関する拡張forループ for (int value : map.values()) { System.out.println(value); } System.out.println();
  74. 74. 名前と年齢をMapを使って表現する例 (続き) // キーに関する拡張forループでも値を得る for (String name: map.keySet()) { System.out.println(name + " => " + map.get(name)); } System.out.println(); // キーBobの値を得る System.out.println("Bobの値 = " + map.get("Bob")); } } // キーFredの値を得る System.out.println("Fredの値 = " + map.get("Fred"));
  75. 75. エントリ • キーと値のペアをエントリ(entry)と呼ぶ • Map<String, Integer>のエントリは Map.Entry<String, Integer>になる ▫ すべてのエントリ(これは集合になる)を得るメ ソッドはentrySet ▫ すべてのキー(これも集合)を得るメソッドは keySet ▫ すべての値(これは要素に重複があるので集合で はない)を得るメソッドはvalues
  76. 76. Collection<E> • List,Queue,Setの書くインターフェースのスー パーインターフェース • メソッドの引数や戻り値の型として時々使う • 引数にCollectionインターフェースが出てきたら、 その引数には、ArrayListでも、HashSetでも渡 せる • 戻り値にCollectionインターフェースが出てきた ら、拡張forループやiteratorメソッドを使って 要素を得ることが出来る
  77. 77. Iterator<E> • コレクションの要素を繰り返してたどるための イテレータを表すインターフェース • イテレータはCollectionのiteratorメソッドを 使って取得し、hasNextメソッドとnextメソッド を使って要素を順番に得る
  78. 78. Comparator<T> • 比較を行うcompareというメソッドを宣言して いるインターフェース • Comparatorインターフェースは、要素の並べ替 え(ソート)を行うときに使う
  79. 79. Javaコレクションフレームワークの主 なインターフェース List<E> Collection<E> Queue<E> Set<E> ConcurrentMap<K, V> Map<K, V> SortedMap<K, V> Iterator<E> Comparator<T> ListIterator<E>
  80. 80. Vector,Stack,Hashtable • Vector<E>は、ArrayListのように「自動的にサイズ が大きくなる配列」の役割を果たすクラス • Stack<E>は、スタックを実現するクラス • Hashtable<K,V>は、キーと値の対応関係を実現す るクラス • ただし、新しいプログラムでは、これらのクラスは 使わずに以下のクラスを用いる方が高速化する ▫ Vector → ArrayList ▫ Stack → LinkedList ▫ Hashtable → HashMap
  81. 81. 演習問題 • 次のページのコードに対して、以下の問いに答 えなさい 1. ※1の場所に、list.add(1234);という文を書くと どうなるか 2. ※2の文で、Alice、Bob、Chrisのどれが改行付 きで表示されるか 3. ※3の文で、どんな数が改行付きで表示されるか。 なお、1の修正は行わないとする
  82. 82. Question.java import java.util.ArrayList; public class Question { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("Alice"); list.add("Bob"); list.add("Chris"); // ※1 System.out.println(list.get(2)); //※2 System.out.println(list.size()); // ※3 for (String name: list) { System.out.println(name); } } }
  83. 83. 発展問題 • ArrayListの内部構造を参考にして、以下のような MyStringArrayListを作成しなさい。ただし、 java.utilパッケージは使用しないこと <要件> ▫ コンストラクタの中でINITIAL_CAPACITY個の要素 を持つStringの配列を、arフィールドに確保する ▫ addメソッドで要素を追加する。配列arがいっぱい だったら、長さを2倍にした新しい配列を確保した上 で追加する(配列のコピーには System.arraycopy(srcArr, fromPos, dstArr, toPos, len) メソッドを使用しなさい)
  84. 84. 発展問題続き ▫ getメソッドで要素を参照する。添字が範囲外なら、 例外IndexOutOfBoundsExceptionをthrowする ▫ sizeメソッドで格納されている要素数(ar.lengthで はない)を返す
  85. 85. MyStringArrayList.java public class MyStringArrayList { private static final int INITIAL_CAPACITY = 4; private String[] ar; private int sz; public MyStringArrayList() { } public void add(String s) { } public String get(int n) { } public int size() { } }

×