Java 逆引き集 | ワイルドカード(? extends / ? super) — API 汎用性

Java Java
スポンサーリンク

ワイルドカード(? extends / ? super) — API 汎用性

Javaのジェネリクスには ワイルドカード という仕組みがあります。
「型を柔軟に受け取る」ための記法で、APIの汎用性を高めるのに必須です。
代表的なのが ? extends? super


基本の違い

記法意味主な用途
? extends TT またはそのサブクラス読み取り専用(取り出すときに安全)
? super TT またはそのスーパークラス書き込み専用(追加するときに安全)

👉 覚え方:

  • 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) を試すと、ワイルドカードの強みが体感できます。

タイトルとURLをコピーしました