Java でのジェネリックスの使い方まとめ

    はじめに

    異なる型のオブジェクトを Set に入れる方法を調べた.

    Object 型

    すべてのクラスの頂点にたつ Object 型を利用すれば, どんな型だっていれることができる.

    ジェネリックスを利用しない場合は, Collection は Object 型で代入される.

    [sourcecode language=”java” title=””]
    class A {
    public void show () {
    System.out.println ("I’m A");
    }
    }

    class B {
    public void show () {
    System.out.println ("I’m B");
    }
    }
    public class GenericSample {
    public static void main (String[] args) {
    HashSet set = new HashSet ();
    A a = new A ();
    B b = new B ();

    set.add (a);
    set.add (b);

    for (Object x: set) {
    if (x instanceof A) {
    A xx = (A) x;
    xx.show ();
    }
    if (x instanceof B) {
    B xx = (B) x;
    xx.show ();
    }
    }
    }
    }
    [/sourcecode]

    欠点は, set に入れるときに Object 型にキャストされるので, メソッド利用時に, 再度 キャストする必要がある.

    [sourcecode language=”java” title=””]
    for (Object x: set) {
    if (x instanceof A) {
    A xx = (A) x;
    xx.show ();
    }
    if (x instanceof B) {
    B xx = (B) x;
    xx.show ();
    }
    }
    [/sourcecode]

    ジェネリックス型

    利用時にキャストするのが面倒. そんな面倒くささを払拭するのが, Java のジェネリックスという機能.

    コンパイル時にのみ型チェックが行われるが, コードとしてキャストをかかなくていいというメリットがある.

    ジェネリック利用 共通の親クラス

    共通の親クラスを継承させることで,Object の範囲をもう少し狭くする.

    [sourcecode language=”java” title=””]
    import java.util.HashSet;

    public class GenericSample {

    public static void main (String[] args) {
    HashSet set = new HashSet();
    D d = new D ();
    E e = new E ();

    set.add (d);
    set.add (e);

    for (C x: set) {
    x.show ();
    }
    }
    }

    abstract class C {
    public abstract void show ();
    }

    class D extends C {
    public void show () {
    System.out.println ("I’m D");
    }
    }

    class E extends C {
    public void show () {
    System.out.println ("I’m E");
    }
    }
    [/sourcecode]

    これだと, instanceof やキャストを省略できる.

    ジェネリック型を定義する

    ジェネリック型を定義してみる.

    定義をするためには,

    • <> で囲まれた記号をクラス名の定義につける
    • <> で囲んだ記号で, 型を置き換える.

    Example

    下の例では, ジェネリックスクラスを自分で定義することで, C,D クラスを E クラス一つで表現している.

    [sourcecode language=”java” title=””]
    import java.util.HashSet;
    import java.util.Set;

    public class GenericsSample2 {
    public static void main (String[] args) {
    C c = new C ();
    c.add (1);
    System.out.println (c.get ());

    D d = new D ();
    d.add ("Hello");
    System.out.println (d.get ());

    E e = new E();
    e.add(1);
    System.out.println(e.get());

    E f = new E();
    f.add("Hello");
    System.out.println(f.get());
    }
    }

    class C {
    private Set set = new HashSet();

    void add (Integer i) {
    set.add (i);
    }

    Integer get () {
    for (Integer i : set) {
    return i;
    }
    return -1;
    }
    }

    class D {
    private Set set = new HashSet();

    void add (String str) {
    set.add (str);
    }

    String get () {
    for (String s : set) {
    return s;
    }
    return null;
    }
    }

    class E {
    private Set set = new HashSet();

    void add (T i) {
    set.add (i);
    }

    T get () {
    for (T i : set) {
    set.clear ();
    return i;
    }
    return null;
    }
    }
    [/sourcecode]

    ジェネリックスの名前付け

    慣例があるようだ.

    異種コンテナの実装

    最後に, Effective Java から, エレガントなジェネリックスの使い方の引用.

    [sourcecode language=”java” title=””]
    import java.util.Map;
    import java.util.HashMap;

    public class GenericsSample3 {
    public static void main (String[] args) {
    Favorites f = new Favorites ();
    f.putFavorite (String.class, "Java");
    f.putFavorite (Integer.class, 0xcafebebe);

    String s = f.getFavorite (String.class);
    int i = f.getFavorite (Integer.class);

    System.out.println (s + i);
    }
    }

    class Favorites {
    private Map, Object> favorites =
    new HashMap, Object>();

    public void putFavorite (Class type, T instance) {
    if (type == null)
    throw new NullPointerException ();
    favorites.put (type, instance);
    }

    public T getFavorite (Class type) {
    return type.cast (favorites.get (type));
    }
    }
    [/sourcecode]

    Environment

    • Java 1.7