ワイルドカード(? extends / ? super) — API 汎用性
Javaのジェネリクスには ワイルドカード という仕組みがあります。
「型を柔軟に受け取る」ための記法で、APIの汎用性を高めるのに必須です。
代表的なのが ? extends と ? super。
基本の違い
| 記法 | 意味 | 主な用途 |
|---|---|---|
? extends T | T またはそのサブクラス | 読み取り専用(取り出すときに安全) |
? super T | T またはそのスーパークラス | 書き込み専用(追加するときに安全) |
👉 覚え方:
- extends → 読む(Producer)
- super → 書く(Consumer)
これは「PECS原則(Producer Extends, Consumer Super)」と呼ばれます。
コード例で理解する
1. ? extends — 読み取り専用
List<? extends Number> list = List.of(1, 2, 3);
// 取り出しは安全
Number n = list.get(0);
// 追加はできない
// list.add(10); // コンパイルエラー
Java👉 「Numberのサブクラス(Integer, Doubleなど)なら何でもOK」。
ただし、どの型か分からないので追加はできない。
2. ? super — 書き込み専用
List<? super Integer> list = new ArrayList<Number>();
// 追加は安全
list.add(10); // IntegerはOK
// 取り出しはObject型になる
Object o = list.get(0);
Java👉 「Integerのスーパー型(Number, Objectなど)なら何でもOK」。
追加は安全だが、取り出すときは型が分からないので Object 扱い。
例題で練習
例題1: 数値リストの合計(? extends Number)
static double sum(List<? extends Number> nums) {
double total = 0;
for (Number n : nums) {
total += n.doubleValue();
}
return total;
}
System.out.println(sum(List.of(1, 2, 3))); // Integerリスト
System.out.println(sum(List.of(1.5, 2.5, 3.5))); // Doubleリスト
Java👉 「Numberのサブクラスなら何でも受け取れる」柔軟なAPI。
例題2: 要素追加ユーティリティ(? super T)
static <T> void addAll(List<? super T> list, T... items) {
for (T item : items) list.add(item);
}
List<Object> objs = new ArrayList<>();
addAll(objs, "A", "B", "C"); // Stringを追加
addAll(objs, 1, 2, 3); // Integerも追加
Java👉 「Tのスーパー型なら受け取れる」ので、追加が安全。
例題3: PECS原則の実感
// Producer Extends
List<? extends Number> src = List.of(1, 2, 3);
Number n = src.get(0); // 読むのは安全
// Consumer Super
List<? super Integer> dst = new ArrayList<Number>();
dst.add(100); // 書くのは安全
Javaテンプレート集
読み取り専用(extends)
void process(List<? extends BaseType> list) {
for (BaseType x : list) {
// 読み取り処理
}
}
Java書き込み専用(super)
void addItems(List<? super SubType> list, SubType item) {
list.add(item);
}
Java汎用ユーティリティ
static <T> void copy(List<? extends T> src, List<? super T> dst) {
for (T item : src) dst.add(item);
}
Javaまとめ
? extends T→ 読み取り専用(Producer)? super T→ 書き込み専用(Consumer)- PECS原則: Producer Extends, Consumer Super。
- API設計: 「入力は extends」「出力先は super」で柔軟に。
👉 練習課題として「コピー関数」を作り、copy(List<? extends T> src, List<? super T> dst) を試すと、ワイルドカードの強みが体感できます。
