// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。

#contents

***Genericsって [#b7f430d9]
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と使う [#ve9231f1]
先は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と使う [#df2a00c8]
次は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);
   }
 }

**自分で作ってみる [#z56d2b36]
Genericsの使い方は何となく分かってきたので、次はGenericsなクラスを自分で作ってみたいと思います。作る観点というかどういうときにGenerics型を導入するかというと、たとえばインタフェースが共通ってわけじゃないけど同じ機能を提供したいとき、といえばいいでしょうか。たとえば java.util.List<E> に定義された
 E get(int index);
などは、Eはインタフェースは共通ではないけど(共通があるとしたらjava.lang.Objectですね)、getでindex番目のオブジェクトを返す機能という意味では共通ですね。

他には、あるサービスを取得するメソッドを作ろうと思ったときに(各サービスは、メソッド名が共通じゃないから同じインタフェースにはできない)
 <T> T getService(Class type);
みたいにクラスを渡してサービスを取得するメソッドをパラメタ化する、とかですかね。ちなみにこれはメソッドのパラメータ化といって、クラス全体じゃなくてメソッドだけをパラメタ化しています。(後述)



**クラスのパラメータ化 [#m8abe496]
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なら何でもいいって事になります。


***パラメタはサブクラスでもいい [#d49c110f]
 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) {}
ってかきます。

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


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


public class ServiceFactory {
 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型が返りますってことができるわけです。フレームワークとかを作るときに使いそうですね。型を指定して、この型のサービスくれーみたいな。。


----
この記事は
#vote(おもしろかった[6],そうでもない[3])
#vote(おもしろかった[18],そうでもない[4])
- Genericsについて、クラスのパラメタ化はクラスの定義で<T>とか書く。メソッドだけのパラメタ化ってのもある。 -- [[きの]] &new{2007-06-22 (金) 15:46:20};

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS