26 Nov 2014, 13:47

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

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    下の例では, ジェネリックスクラスを自分で定義することで, C,D クラスを E クラス一つで表現している.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> import java.util.HashSet;<br /> import java.util.Set;
  </p>

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

  <p>
    D d = new D ();<br /> d.add ("Hello");<br /> System.out.println (d.get ());
  </p>

  <p>
    E<Integer> e = new E<Integer>();<br /> e.add(1);<br /> System.out.println(e.get());
  </p>

  <p>
    E<String> f = new E<String>();<br /> f.add("Hello");<br /> System.out.println(f.get());<br /> }<br /> }
  </p>

  <p>
    class C {<br /> private Set<Integer> set = new HashSet<Integer>();
  </p>

  <p>
    void add (Integer i) {<br /> set.add (i);<br /> }
  </p>

  <p>
    Integer get () {<br /> for (Integer i : set) {<br /> return i;<br /> }<br /> return -1;<br /> }<br /> }
  </p>

  <p>
    class D {<br /> private Set<String> set = new HashSet<String>();
  </p>

  <p>
    void add (String str) {<br /> set.add (str);<br /> }
  </p>

  <p>
    String get () {<br /> for (String s : set) {<br /> return s;<br /> }<br /> return null;<br /> }<br /> }
  </p>

  <p>
    class E<T> {<br /> private Set<T> set = new HashSet<T>();
  </p>

  <p>
    void add (T i) {<br /> set.add (i);<br /> }
  </p>

  <p>
    T get () {<br /> for (T i : set) {<br /> set.clear ();<br /> return i;<br /> }<br /> return null;<br /> }<br /> }<br /> [/sourcecode]
  </p>
</div>

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

<div class="outline-text-3" id="text-unnumbered-7">
  <p>
    慣例があるようだ.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://java.keicode.com/lang/generics-naming.php">名前付けルール &#8211; Java 入門</a>
    </li>
  </ul>
</div>

異種コンテナの実装

最後に, 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