Java 1.5からはクラスに型パラメータを渡せるようになった。 型パラメータを持つクラスやインタフェースがジェネリッククラスやジェネリックインタフェースである。 標準ライブラリで代表的なものはコレクションクラスで、List<T>
やMap<K, V>
が該当する。
ジェネリックとは、ようはクラスやインタフェースが扱う型をプログラマが指定できるクラスやインタフェースのことだ。 ジェネリックのメリットは、コードに型を自在に差し替える柔軟性を持たせられること。さらにコンパイル時に型の不整合を検出できるためコードが型安全になり、実行時にCastException
が発生しなくなることだ。
ジェネリッククラスの使い方
型パラメータを持つクラスは以下のように定義できる。 型パラメータの名前は何でも良いが、慣例で大文字1文字の名前をつける事が多い。 クラス中では型パラメータの型を使って変数やメソッドを定義することができる。
// ジェネリッククラスの例
class GenericClass<T>{
// 型Tのオブジェクトを受け取り
// そのまま結果を返すメソッドの例
public T method(T obj){
return obj;
}
}
イメージとしてはクラス中の型パラメータは実行時に指定されたクラスで読み替えて処理される。 例えばObject
クラスで初期化したジェネリッククラスは、以下のコードと同じように動作する。
GenericClass<Object> gc = new GenericClass<Object>;
// TをObjectで読み替えたジェネリッククラスのイメージ
class GenericClass{
public Object method(Object obj){
return obj;
}
}
型パラメータを複雑にしているのは、extends指定とワイルドカードだろう。 以下ではextends指定とワイルドカードを例示して説明する。
extends指定
型パラメータのextends指定は型パラメータが特定の型であることを要求する。 その効用としてジェネリッククラスの中では要求したクラスの機能を自由に使うことができる。 Clazz
とそのサブクラスSubClazz
が定義されているとして、これらのクラスを受け付けるGenericClass
を定義してみよう。
public class Clazz{
public void function(){
// 処理
}
}
public class SubClazz extends Clazz{
// SubClazzの実装
}
public class GenericClass<T extends Clazz>{
public void method(T obj){
// Clazzのメソッドの呼び出し
obj.function();
}
}
このGenericClass
を使う場合は、T
はClazz
かそのサブクラスでなければならない。
GenericClass<Object> gc1 = new GenericClass<Clazz>; // Clazzが型パラメータ
GenericClass<Object> gc2 = new GenericClass<SubClazz>; // SubClazzが型パラメータ
以下のようにClazz
と継承関係にない型パラメータを渡すとコンパイルエラーとなる。
// コンパイルエラー!
GenericClass<Object> gc = new GenericClass<Object>;
ワイルドカード
プログラムでジェネリッククラスの性質のみに関心があり、ジェネリッククラスの型パラメータにまでは関心がない場合がある。 このような型指定にはワイルドカード?
が利用できる。 例えば何らかのGenericClass
を引数に取るメソッドは、以下のように定義できる。
public static void wildcardMethod(GenericClass<?> gc){
// 何らかのGenericClassに対する処理
}
なお型パラメータの継承関係はジェネリッククラスの型には何ら影響を与えない。 GenericClass<Clazz>
とGenericClass<SubClazz>
は別の型である事は注意が必要だ。 よって以下のコードはコンパイルエラーとなる。
// コンパイルエラー!
GenericClass<Clazz> gc = new GenericClass<SubClazz>();
Clazz
とSubClazz
を型パラメータに受け取ったジェネリッククラスを受け入れられる変数の型は、ワイルドカードを使ったGenericClass<?>
だけである。
GenericClass<?> gc1 = new GenericClass<Clazz>();
GenericClass<?> gc2 = new GenericClass<SubClazz>();
Javaのジェネリックについては、Effective Javaの第5章が詳しい。
ピアソンエデュケーション
売り上げランキング: 88,031