appendix> util> generics TOPUPPREVNEXT

型のパラメータ

インターフェースやクラスの定義をする際、型(クラス)をパラメータとして記述する 総称 とか ジェネリックス Generics と呼ばれている機能が J2SE 5.0 から提供されています。 これによりコレクションの要素の型を限定できるようになりました。

1.4 以前では、コレクションに 要素を add し、 get すると常に Object クラスの要素が返され、 通常はキャストをして使わなければなりませんでした。 ジェネリックを使うと、 「String」の ArrayList とか、「Number クラスを継承するクラス達」の SortedSet といったものを 取り扱えるようになります。

ジェネリックスはコンパイラの機能であり、コンパイル時に型検査がされ、 Object クラスを処理するコードを生成し、 キャストを行うコードが挿入されます。 実行時の型検査が行われるわけではありません。

【型のパラメータ】

コレクションのインターフェースの説明に
Collection<E> とか List<E>
といった記述がありますが、これを 型変数の宣言といい、 E の部分にクラス名やインターフェース名がはいることを示しています。

たとえば、 Collection<String> 、Collection<JLabel> 、あるいは List<Integer> といった形で参照されます。 参照されるとたとえば、String だけからなる Collection 、 JLabel だけからなる Collection 、Integer の List などのように要素の型が限定されたコレクションを表します。 一旦 E に String を割り当てたら、その定義についての E は全て String で置き換えて読みます。 もし <T> のように異なった変数が現れた場合には、別のクラスを対応付けることができます。

対応付けができるのはクラスの名前です。 int とか double といった基本データ型を指定してはいけません。

型変数の宣言を書ける場所は以下の3つです。

クラス宣言のクラス名の直後
インターフェース宣言のインターフェース名の直後
メソッド宣言の戻り値の型の直前
上記以外の場所の <...> は型変数の参照になります。

変数には任意の識別子を用いることができますが、通常つぎのような名前を使う習慣になっています。

大文字1文字を用いる。
コレクションの場合、要素(Element)をあらわす E を用いる。
マップには、キー(Key)と値(Value)をあらわす K V を用いる。
その他の場合、型(Type)をあらわす T を用い、別の型が必要ならば S R などを用いる。

複数の変数を宣言する場合は、コンマで区切ってならべます。

インターフェースの例 StackInterface.java

クラス定義の例 Stack.java

クラス参照の例 StackDemo1.java

実行例

上記3ファイルをカレント・ディレクトリにダウンロードし、StackDemo1.java をコンパイル・実行した例

StackDemo1-1.gif

StackDemo1.java の 8〜9行目は int 型が Integer 型に自動的に型変換され、 20〜21行目では、int 型や double 型から Integer型や Double型に自動的に型変換されています。 これは J2SE 5.0 で提供された ボクシング という機能です。

20〜22行目の ns.push のパラメータは Number クラスが要求されていますが、 Integer 型 や Double 型は Munber型 を継承していますからそのまま渡せます。 26〜28行目は、ns.pop の型は Number ですので、 54〜57行目に書かれている convert が呼ばれます。

6行目は、型を限定しないクラス参照です。 31〜34行目のように様々なクラスを渡せますが、無検査のむね警告が表示されます。 コンパイルのオプションに −Xlint:unchecked を指定すると、 上図のように警告が表示されます。このオプションを指定しない場合は、 警告がある旨のメッセージが1行表示されます。 38〜41行目の xs.pop は Object 型とみなされ、58〜80行目の convert が呼ばれます。 ここでは、返された値をしかるべき型にキャストをしてから使います。 Integer 型と Double 型は Menber 型を継承していますから、64〜71行目を削除すれば、 Menber 型として処理されます。

【型のワイルドカード】

型変数を参照する個所に
Collection<?> とか List<?>
といった記述がありますが、この <?> は全てのクラスを指します。

型変数の参照では継承関係は考慮されません。 <Object> とあれば、 Object クラスそのものを指します。

ArrayList<Object>
と書くと、Object クラスを要素とする ArrayList になります。 Object クラスを継承するクラス(任意のクラス)を要素とする ArrayList
ArrayList<?>
と書かなければいけません。

【型の限定】

Collection<? extends T> とか List<? extends T>
は、クラス T および T の子クラス 、 あるいは、 インターフェース T を実装するクラスを表します。
Collection<? super T> とか List<? super T>
は、クラス T および T の親クラスに対応します。

更新日:2005-00-00