Javaで要素数が変化するデータをまとめて扱う場合は、通常Collection Frameworkのクラスを使用します。Collection Frameworkに属する実装クラスは、List、SetまたはMapのインターフェイスを持っており、それぞれ以下の表のような特徴があります。なお、ListとSetインターフェイスを持つ実装クラスはCollectionインターフェイスも持っています。
Collection Frameworkのインターフェイスと実装クラス
|
インターフェイス |
特徴 |
実装クラスの例 |
|
List |
要素の順序を保持。同一要素も複数保持可能 |
ArrayList,LinkedList,Vector |
|
Set |
要素の順序は保持しない。同一要素は複数保持不可 |
HashSet,TreeSet,LinkedHashSet |
|
Map |
keyとvalueを組にして要素として保持。要素の順序は保持しない。同一keyの要素は複数保持不可 |
HashSet,TreeSet,LinedHashSetHashMap, TreeMap,HashTable |
|
List、Set、Mapインターフェイスを持つ実装クラスには複数のものがあり、それぞれには特徴があります。例えば同じListインターフェイスを持つArrayListとLinkedListを比較すると、LinkedListを使った方が、リスト途中に要素を挿入する操作が高速で行えますが、使用メモリ量はArrayListよりも多くなってしまいます。そのため、すでにデータが格納されているインスタンスをいったん別のCollection Framework型にコピーして変換を行い、変換後のインスタンスに対して操作を行った方が結果として高速に処理できる場合があります。また、すでにデータが格納されているインスタンスをあるメソッドの引数として渡したいが、型が異なるためそのまま渡すことができない場合も、型の変換が必要となります。
本Tipsでは型の異なるCollection同士、または型の異なるMap同士の変換と、MapをCollectionに変換する方法を紹介します。
Collectionインターフェイスを持つクラスはCollectionを引数として取るコンストラクタがあります。同様に、Mapインターフェイスを持つクラスはMapを引数として取るコンストラクタがあります。これらのコンストラクタを使用すること、異なるCollection型同士または異なるMap型同士でデータをコピーすることで型変換を行うことができます。
また、既存のCollectionインターフェイスを持つインスタンスのclear()メソッドとaddAll(Collection c)メソッドを使用すると、別のCollectionインターフェイスを持つインスタンスの全内容を当該インスタンスにコピーすることができます。Mapインターフェイスを持つクラスについても同様です。
なお、これらの方法は内容を「コピー」することで型変換を行うため、変換後のインスタンスに対して行われた変更は変換前のインスタンスには反映されませんし、逆も同じです。注意してください。
Collectionインターフェイスを持つ異なる実装型同士で、またMapインターフェイスを持つ異なる実装型同士で、格納されている内容をコピーして型の変換を行うサンプルソースと実行結果を以下に示します。
サンプルソース
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Collection2Collection {
public static void main(String[] args) {
List a = new ArrayList();
a.add("foo");
a.add("bar");
a.add("baz");
a.add("foo");
Set s = new HashSet(a);//ArrayListをHashSetに変換。Setなので順序関係は失われ、重複する要素はただ1つになる
for (Iterator i = s.iterator(); i.hasNext();) {
System.out.println((String)i.next());
}
System.out.println("----");
a.clear();
a.addAll(s);//HashSetを既存のArrayListインスタンスにコピーすることで変換
for (Iterator i = a.iterator(); i.hasNext();) {
System.out.println((String)i.next());
}
System.out.println("----");
Map tm = new TreeMap();
tm.put(new Integer(1), "foo");
tm.put(new Integer(2), "bar");
tm.put(new Integer(3), "baz");
Map hm = new HashMap(tm);//TreeMapをHashMapに変換
for (Iterator i = tm.keySet().iterator(); i.hasNext();) {
Integer num = (Integer)i.next();
System.out.println("" + num + " " + hm.get(num));
}
}
} |
実行結果
foo
baz
bar
----
foo
baz
bar
----
1 foo
2 bar
3 baz |
あるMapインターフェイスを持つクラスのインスタンスから、すべてのkey、すべてのvalue、あるいはkeyとvalueの全組をCollectionとして取り出すことができます。すべてのkeyを取り出すには当該インスタンスのkeySet()、すべてのvalueを取り出すには当該インスタンスのvalues()、keyとvalueの全組を取り出すには当該インスタンスのentrySet()メソッドを使用します。keySet()の戻り値はSet、entrySet()の戻り値はjava.util.Map.Entryを要素として持つSetですが、SetはCollectionインターフェイスを持つため、どちらもCollectionとして扱うことができます。
これらのメソッドにより取得したCollectionは、元のMapインスタンスをあたかもCollectionとして「見せている」ものです。ですので、取得したCollectionの内容を修正すると、元のMapインスタンスの内容も変化します。1つのMapインスタンスから同時に複数のCollectionを取得した場合は、それらの内容も同時に変化します。
MapをCollectionに変換するサンプルソースと実行結果を以下に示します。
サンプルソース
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class Map2Collection {
public static void main(String[] args) {
Map m = new TreeMap();
m.put(new Integer(1), "foo");
m.put(new Integer(2), "bar");
m.put(new Integer(3), "baz");
Collection keys = m.keySet();//すべてのkeyをCollectionとして取り出す
Collection values = m.values();//すべてのvalueをCollectionとして取り出す
Collection entries = m.entrySet();//key/valueのすべての組をCollectionとして取り出す
for (Iterator i = keys.iterator(); i.hasNext();) {
System.out.println("key:" + (Integer)i.next());
}
for (Iterator i = values.iterator(); i.hasNext();) {
System.out.println("value:" + (String)i.next());
}
for (Iterator i = entries.iterator(); i.hasNext();) {
Map.Entry ent = (Map.Entry)i.next();
System.out.println("key:" + (Integer)ent.getKey() + " value:" + (String)ent.getValue());
}
System.out.println("----");
values.remove("foo");// value="foo"となる要素を削除
for (Iterator i = entries.iterator(); i.hasNext();) {
Map.Entry ent = (Map.Entry)i.next();
System.out.println("key:" + (Integer)ent.getKey() + " value:" + (String)ent.getValue());
}
System.out.println("----");
keys.remove(new Integer(2));// key=2となる要素を削除
for (Iterator i = entries.iterator(); i.hasNext();) {
Map.Entry ent = (Map.Entry)i.next();
System.out.println("key:" + (Integer)ent.getKey() + " value:" + (String)ent.getValue());
}
}
}
|
実行結果
key:1
key:2
key:3
value:foo
value:bar
value:baz
key:1 value:foo
key:2 value:bar
key:3 value:baz
----
key:2 value:bar
key:3 value:baz
----
key:3 value:baz |