Java のジェネリックスのワイルドカード型
ジェネリックスのワイルドカード型とは
クラスの定義としてではなく、メソッド定義にて通常の型として「ジェネリックスの型」を指定することもできます。
次の例の中で printAll() というメソッドは、String のコレクション Collection<String> 型のコレクションを受け取り、 その要素を出力しています。
package com.keicode.java.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class TestApp {
public static void main(String[] args) {
// String のリスト
List list1 = new ArrayList<>();
list1.add("Hello");
list1.add("World!");
printAll(list1);
}
public static void printAll(Collection<String> col) {
for (String o : col) {
System.out.println(o);
}
}
}
実行結果は次のようになります。
Hello
World!
このコレクションはジェネリックスを用いて型指定していますが、これを使う側でジェネリックスの型 T 毎に使わないといけないのでは不便です。
例えば上の例では String 型のコレクションを受け取るメソッドを作りましたが、その他 Integer 型のコレクション、Object 型のコレクションという風にそれぞれ別個に扱わないといけないとしたら面倒です。
そこで、ワイルドカード型 (wildcard types) が利用できます。
ワイルドカードは ? で表され、 Collection<?> とすれば、任意の型のコレクションということになります。
package com.keicode.java.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class TestApp {
public static void main(String[] args) {
// String のリスト
List list1 = new ArrayList<>();
list1.add("Hello");
list1.add("World!");
printAll(list1);
// Integer のリスト
List list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
printAll(list2);
}
public static void printAll(Collection<?> col) {
for (Object o : col) {
System.out.println(o.toString());
}
}
}
Upper Bound ワイルドカード型
「任意の型」のコレクションではなく、例えば 「Person クラスから派生した全てのサブクラス」のコレクションを受けとるのであれば、 <? extends Person> と表記できます。
public static void printAll(Collection<? extends Person> col){
// Do something
}
この場合のように派生クラス (サブクラス) なら何でも、と指定する場合は、? 記号と extends というキーワードを用います。
このとき Upper Bound ワイルドカード型 といいます。
Lower Bound ワイルドカード型
Upper Bound ワイルドカードでは派生クラスを指定しましたが、スーパークラスをワイルドカードで指定する方法もあります。
「このクラスのスーパークラスなら何でも」という指定方法です。
この場合は、次のようにワイルドカード ? と super というキーワードで表現します。
<? super クラス名>
このとき Lower Bound ワイルドカード型 といいます。
Bounded ワイルドカード型のまとめ
次のようなクラス階層があったとします。
そこで、この時に <? extends "PC Device"> に含まれるクラスは以下の緑で塗りつぶしたクラス全部です。
一方、<? super "Input Device"> に含まれるクラスは以下の緑色のクラスだけです。
このように、クラスツリーの上方にも下方にも型を指定することが可能です。