今回はジェネリックスに関するメモ。java5から登場した<>のことである。最初は意味不明だったけど、少しはわかった……気がする。
そもそもジェネリックスって何なのか?
- 許されるオブジェクト型が何であるかをコンパイラに知らせるための機構
- 原型(List<E>ではなく、Listとして使う)の場合、それは判断できない
- 要素に入るのがIntergerなのかStringなのかわからないとチェックできない
- 原型を使うとジェネリックスの安全性と表現力のすべてを失うことになる
- コンパイラはジェネリックスの定義に従いキャストを実施する
- ソース側ではキャスト不要
- コンパイラが隠れたキャストを挿入し、キャストが失敗しないことを保証する
- ジェネリックス型
- 型パラメータを宣言に持つクラスやインタフェース
- 実行時には消える
- instanceof Set<E> ではなく instanceof Set
ジェネリックスの指定
- パラメータ型は不変である
- List<Number>の要素に指定できるのはNumberのみ。Integerでは駄目
- List<E>でEをNumberとして指定した場合、そのクラスで登場するEはすべてNumberでないといけない
- 境界ワイルドカード
- ? extends E
- Eの子クラスならOKという指定:相手が生産者(プロデューサー)
- ? super E
- Eの親クラスならOKという指定 :相手が消費者(コンシューマ)
- 生産者か消費者を表す入力パラメータに対してワイルドカード型を使用する
- 戻り値としてはワイルドカード型を使用しない
- クライアントにワイルドカード型の使用を強制してしまうのはよくない
- 非境界ワイルドカード型
配列とリストの違い
- 配列:共変(covariant)
- Sub extends Superならば Sub は Superの子クラス
- Sub[]の要素にSuperのものが入れられる
- コンパイル時の型安全性は提供しない
- 実行時の型安全性は提供する
- ArrayStoreExceptionやClassCastExcepion
- 具象化不可能型の配列は作成できない:Eの配列等
- リスト:不変(invariant)
ジェネリックスメソッドのポイント
- staticのユーティリティメソッドはジェネリック化のよい候補
- 型パラメータを宣言する型パラメータリストはメソッドの修飾子とメソッドの戻り値型の間に入る
- 使用するとき、メソッドの場合は型パラメータの値を指定する必要がない→引数の型でパラメータ型が何でないといけないかわかる
public static <K,V> HashMap<K,V> newHashMap() { return new HashMap<K,V>(); } Map<String, List<String>> listMap = newHashMap(); <K,V>が型パラメータリスト K:String,V:List<String> とコンパイラが型推論してくれる
- 型パラメータがその型パラメータ自身が関係する何らかの式で制限することも可能→再帰型境界
- public static <T extends Comparable<T>> T max(List<T> list)
参考文献
Effective Java 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2008/11/27
- メディア: 単行本(ソフトカバー)
- 購入: 77人 クリック: 936回
- この商品を含むブログ (266件) を見る