GenericsとAutoboxingの簡単なサンプル
Generics(ジェネリクス)の簡単なサンプルを書いてみる。
GenericsとAutoboxing/unboxingは、密接に結びついていて、以下に示すような簡単なサンプルでは、「どちらの仕様が機能しているのか」わかりづらい。
はじめに、1.4系までのシンタックスで簡単なコードを書いてみる。
package test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * GenericsとAutoboxing/unboxingを用いた簡単なサンプル * (1.4系のシンタックス版) * Listインターフェイス、Mapインターフェイスを利用する例。 * */ public class ExampleGenerics1 { /** * Main * List型のコレクションに整数を格納し、数字の取り出しと計を求める。 * Map型のコレクションから、要素を取得する。 * * @param args ;利用しない。 * */ public static void main(String[] args) { // --- Listに整数1を追加する。--- List aList = new ArrayList(); // (A) 1をラッパークラスIntegerでラップする。 aList.add(new Integer(1)); System.out.println("listed value = " + aList.get(0)); // 上のListから整数1を取り出す。s // (B) 取り出してラッパークラスにCastした後、1に足す。 int sum = 1 + ((Integer)aList.get(0)).intValue(); System.out.println("test sum = " + sum); // --- 整数をキーにするMapを作る。 --- Map map = new HashMap(); // (C) キーとなる整数をラップする。 map.put(new Integer(1),"いちご"); map.put(new Integer(2),"ばなな"); // (D) 1番目を取り出すために1をIntegerでラップして、取り出す。 System.out.println("first element is " + map.get(new Integer(1))); } }
これを実行した結果は以下のようになる。
listed value = 1
test sum = 2
first element is いちご
これを、Java5(Tiger)のシンタックスに書き直して見る。
package test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * GenericsとAutoboxing/unboxingを用いた簡単なサンプル * (Java5系のシンタックス版) * Listインターフェイス、Mapインターフェイスを利用する例。 * */ public class ExampleGenerics2 { /** * Main * List型のコレクションに整数を格納し、数字の取り出しと計を求める。 * Map型のコレクションから、要素を取得する。 * * @param args ;利用しない。 * */ public static void main(String[] args) { // --- Listに整数1を追加する。 --- // (a) GenericsでListの型を宣言。 List<Integer> aList = new ArrayList<Integer>(); // (b) Autoboxingで整数をそのままadd。 aList.add(1); System.out.println("listed value = " + aList.get(0)); // 上のListから整数1を取り出す。 // (c) Auto-unboxingで整数をそのまま取り出す。 int sum = 1 + aList.get(0); System.out.println("test sum = " + sum); // --- 整数をキーにするMapを作る。 --- // (d) GenericsでMapを宣言。 Map<Integer,String> map = new HashMap<Integer,String>(); // (e) Autoboxingで整数、文字列をそのままput。 map.put(1,"いちご"); map.put(2,"ばなな"); // (f) Auto-unboxingで整数をKeyにそのまま取り出す。 System.out.println("first is " + map.get(1)); } }
サンプル中にも示したが、
1.Genericsによって、List
,Map ,ArrayList ,HashMap といった、型と具象クラスの宣言ができるようになった(List などと書く。Eは、Elementの頭文字)。
2.Autoboxing/unboxingによって、基本型(プリミティブ型)と参照型(オブジェクト型)の間の行き来をする際に、ラッパークラス(Integer, Float, Boubleなど)を使用しなくてもよくなった。
によって、コードがスッキリかけるようになった。
1.4系まで、コレクションフレームはオブジェクト(java.lang.Object)を格納することで汎用性を維持していたが、副作用として、「キャストすること」、「基本型を格納する際には、ラッパーでオブジェクト化すること」が必須になっていた。
Genericsの導入の動機に、「キャストの間違いが、実行時エラー(Runntime例外)としてしか発見できない」というものがあった。
だが、Genericsによって、コレクションフレームワークのインターフェイス、具象クラスの利用時に格納するオブジェクトの型を宣言できるようになった。そして、この「宣言した型に合致しないオブジェクト」が格納されようとした際に、「コンパイルエラー」として間違いを発言させられるようになった。
これが、Java5により「品質の向上」と言われる部分の一つ。
また、Autoboxing/unboxingにより、「ラッパーで包んだり、それから基本型を取り出したり」といった操作さ不要になった。これは、リリースノートにかかれた「drudgery(つまらない)コードの削減」の一つである。
Genericsの使い方としては、Autoboxingと絡めたこのような使い方が一番多いだろう。