Top / Java / Tiger / Generics

Genericsって

Genericsとは、C++のテンプレートのような機能で、クラスやインタフェースをパラメータ化するための技術だそうです。Genericsを使うことによって、

  • よけいなCastをなくして、コンパイル時に型チェックをできるようになる
  • いちいちキャストするコーディングをする必要がなくなる

などいろいろな効果があるようです。

たとえば

List list = new ArrayList();
list.add(new Integer(10));
String str = (String) list.get(0);

などのエラーは実行時しか検知できませんか、Genericsを使って記述すると

List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(10));
String str = (String) list.get(0); <-コンパイルエラーとなる

となりコンパイルエラーとなります。コンパイル時にエラーとなるので、保守性が向上するわけですね。

さて構文ですが、

List<Integer> list = new ArrayList<Integer>();

などとクラス名<クラス名>という構文になります。http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/List.html を見てもわかるとおりJavaDoc?

インタフェース List<E>

と宣言されています。

Iteratorと使う

先はListの例でしたが、次はIteratorです。Listの返り値はパラメタ化Iteratorなので e.next() したときにIntegerにキャストがいらなくなります。

public class GenericsSample {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<Integer>();//IntegerでListを作成
    for (int i = 0; i < 10; i++) {
      list.add(new Integer(i));
    }

    Iterator<Integer> e = list.iterator();//このIteratorはIntegerのIterator
    while (e.hasNext()) {
      Integer integer = e.next(); //Integerにキャストがいらない
      System.out.println(integer);
    }

  }
}

Mapと使う

次はMapです。key,valueがあるので

Map<String, Integer> map = new HashMap<String, Integer>();

という指定になります。

public static void main(String[] args) {
  Map<String, Integer> map = new HashMap<String, Integer>();
  for (int i = 0; i < 10; i++) {
    map.put("key_" + Integer.toString(i), new Integer(i));
  }
  Set<String> keys = map.keySet(); //返り値のSetはStringのSet
  Iterator<String> e = keys.iterator(); //そのSetのIteratorはStringのIterator
  while (e.hasNext()) {
    String key = e.next(); //だからキャストがいらない
    Integer integer = map.get(key); //ここもキャストがいらない。
    System.out.println(key + ":" + integer);
  }
}

自分で作ってみる

Genericsの使い方は何となく分かってきたので、次はGenericsなクラスを自分で作ってみたいと思います。作る観点というかどういうときにGenerics型を導入するかというと、たとえばインタフェースが共通ってわけじゃないけど同じ機能を提供したいとき、といえばいいでしょうか。たとえば java.util.List<E> に定義された

E get(int index);

などは、Eはインタフェースは共通ではないけど(共通があるとしたらjava.lang.Objectですね)、getでindex番目のオブジェクトを返す機能という意味では共通ですね。

他には、あるサービスを取得するメソッドを作ろうと思ったときに(各サービスは、メソッド名が共通じゃないから同じインタフェースにはできない)

<T> T getService(Class type);

みたいにクラスを渡してサービスを取得するメソッドをパラメタ化する、とかですかね。ちなみにこれはメソッドのパラメータ化といって、クラス全体じゃなくてメソッドだけをパラメタ化しています。(後述)

クラスのパラメータ化

Genericsなクラスを作るには

public interface GenericDao<T, PK extends Serializable> {
  PK create(T newInstance);
  T read(PK id);
  void update(T transientObject);
  void delete(T persistentObject);
}

などとクラスの定義でGenericDao?<T> などと書けばOKです。

上の例の

PK extends Serializable

の部分は引数はSerializableなら何でもいいって事になります。

パラメタはサブクラスでもいい

public class Hoge<T> {
  private T t;
  public Hoge(T t) {
    this.t = t;
  }
  public void exe(List<T> list) {}
}

のばあい、コンストラクタの引数がTなので、TをListとすると

List list=new ArrayList();
Hoge<List> hoge=new Hoge<List>(list);

ってなります。listはListのサブクラスでもOKです。しかし

 public void exe(List<T> list) {}

に関してはたとえばTをNumberだとすると

List<Integer> list = new ArrayList<Integer>();
hoge.exe(list);

はコンパイルエラーとなります。listはList<Integer>なのでList<Number>とは互換性がないって事ですね。

Tのサブクラス、この例だとNumberのサブクラスならいいよって定義したいときは

前: public void exe(List<T> list) {}
後: public void exe(List<? extends T> list) {}

とします。?のワイルドカードを使って、Listの型はTのサブクラスなら何でもいいよっていう定義となります。その他、TのSuperクラスならいいよとか、Tは何でもいいよって書きたいときはそれぞれ

public void exe(List<? super T> list) {}
public void exe(List<?> list) {}

ってかきます。

なんだかわけがわからなくなってきました。

メソッドのパラメータ化

クラスのパラメータ化ではなくて、メソッドだけのパラメータ化って事もできます。たとえば

public class ServiceFactory {
 private Map map = new HashMap();
 public <T> T createService(Class<T> type) {
   return (T) map.get(type);
 }
}

と戻り値の前にGenericsの型を書いておくことで

ServiceFactory factory = new ServiceFactory();
List list = factory.createService(List.class);

そのメソッドだけをパラメータ化することができます。つまりList.classってのを渡したらList型が返りますってことができるわけです。フレームワークとかを作るときに使いそうですね。型を指定して、この型のサービスくれーみたいな。。


この記事は

選択肢 投票
おもしろかった 18  
そうでもない 4  
  • Genericsについて、クラスのパラメタ化はクラスの定義で<T>とか書く。メソッドだけのパラメタ化ってのもある。 -- きの? 2007-06-22 (金) 15:46:20

Top / Java / Tiger / Generics

現在のアクセス:14576


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-10-16 (木) 11:09:40 (1768d)