下限付きワイルドカード
消費側には ? super T を使います。
「下限付きワイルドカード」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
下限付きワイルドカード
? super T は下限付きワイルドカードです。これは「T または T のスーパータイプである、未知の型」を意味します。
List<? super Integer> は、List<Integer>、List<Number>、または List<Object> を参照できます。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? super Integer> a = new ArrayList<Number>();
List<? super Integer> b = new ArrayList<Object>();
a.add(1);
b.add(2);
System.out.println(a + " " + b);
}
}コンシューマーへの書き込み
? super Integer では、任意の Integer(または Integer のサブタイプ)を安全に追加できます。
実際のリスト型が何であっても、少なくとも Integer のスーパータイプのリストなので、Integer は必ず適合します。
import java.util.ArrayList;
import java.util.List;
public class Main {
static void addNumbers(List<? super Integer> dest) {
for (int i = 1; i <= 3; i++) dest.add(i);
}
public static void main(String[] args) {
List<Number> nums = new ArrayList<>();
addNumbers(nums);
System.out.println(nums);
}
}読み取り結果は Object になります
その代わり、? super T のリストから読み取る場合、コンパイラが把握できるのは、要素が T の未知のスーパータイプのいずれかであるということだけです。
読み取り時に安全な唯一の型は Object です。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? super Integer> list = new ArrayList<Number>();
list.add(10);
Object o = list.get(0); // only Object is guaranteed
// Integer i = list.get(0); // would NOT compile
System.out.println(o);
}
}読み取りが制限される理由
List<? super Integer> は、実際には String を格納した List<Object> かもしれません。
そのため、読み取り結果は任意の Object になり得ます。コンパイラは Integer であると保証できないため、読み取り結果は Object にしかなりません。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Object> raw = new ArrayList<>();
raw.add("a string");
List<? super Integer> view = raw; // legal: Object is a supertype of Integer
view.add(5);
System.out.println(view.get(0).getClass().getSimpleName());
}
}コンシューマーのユースケース
メソッドが値を消費(書き込み)するだけの場合は、? super T を使用してください。
宛先コレクションに値を格納するメソッドが、典型的なケースです。
import java.util.ArrayList;
import java.util.List;
public class Main {
static void fill(List<? super String> dest, int count) {
for (int i = 0; i < count; i++) dest.add("item" + i);
}
public static void main(String[] args) {
List<Object> objs = new ArrayList<>();
fill(objs, 3);
System.out.println(objs);
}
}サブタイプの追加も可能です
? super Number では、Number またはそのサブタイプである Integer、Double、Long を追加できます。
下限によって、リストが少なくとも Number を受け入れることが保証されるため、すべてのサブタイプが適合します。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? super Number> list = new ArrayList<Object>();
list.add(1); // Integer
list.add(2.5); // Double
list.add(3L); // Long
System.out.println(list);
}
}Collections.addAll の形式
JDK では、データを受け取る側に下限付きワイルドカードを使用します。たとえば、宛先に要素を追加するジェネリックメソッドなどです。
import java.util.ArrayList;
import java.util.List;
public class Main {
@SafeVarargs
static <T> void addAll(List<? super T> dest, T... items) {
for (T item : items) dest.add(item);
}
public static void main(String[] args) {
List<Object> sink = new ArrayList<>();
addAll(sink, "a", "b", "c");
System.out.println(sink);
}
}super を使う Comparator
実際の使用例として、Comparator<? super T> を使うと、スーパータイプ用に作成されたコンパレータをソートで受け入れられます。
任意の Object を toString で比較するコンパレータで、String のリストをソートできます。
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
Comparator<Object> byString = Comparator.comparing(Object::toString);
List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
names.sort(byString); // List<String>.sort accepts Comparator<? super String>
System.out.println(names);
}
}super と extends は対になる概念です
2つのワイルドカードは正反対の関係にあります。
? extends T:T として読み取れますが、書き込めません。プロデューサーです。? super T:T を書き込めますが、読み取り結果は Object だけです。コンシューマーです。
この対称性が、次に学ぶ PECS ルールの核心です。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? super Integer> consumer = new ArrayList<Number>();
consumer.add(1);
System.out.println("consumer can write: " + consumer);
}
}境界の異なる型の間でコピーする
コピー用メソッドを使うと、2つのワイルドカードを同時に確認できます。? extends T から読み取り、? super T に書き込みます。
import java.util.ArrayList;
import java.util.List;
public class Main {
static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (T t : src) dest.add(t);
}
public static void main(String[] args) {
List<Integer> src = List.of(1, 2, 3);
List<Number> dest = new ArrayList<>();
copy(src, dest);
System.out.println(dest);
}
}ワイルドカードを使わない場合
メソッドが T の読み取りと書き込みの両方を行う場合は、ワイルドカードを使用しないでください。正確な型または名前付き型パラメータを使用します。
ワイルドカードは、読み取り専用または書き込み専用のケースのために存在します。
import java.util.ArrayList;
import java.util.List;
public class Main {
static <T> void swapFirstTwo(List<T> list) {
T tmp = list.get(0);
list.set(0, list.get(1));
list.set(1, tmp);
}
public static void main(String[] args) {
List<String> list = new ArrayList<>(List.of("a", "b"));
swapFirstTwo(list);
System.out.println(list);
}
}理解度チェック
下限付きワイルドカードについての理解を確認しましょう。
まとめ
下限付きワイルドカードについて学びました。
? super Tは、T の未知のスーパータイプを意味します。- T とそのサブタイプを書き込めます(コンシューマー)。
- 読み取り結果はObject だけです。
? extends Tと正反対の関係にあります。
次は、これら2つを結び付けるルール、PECS です。
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<? super Integer> list = new ArrayList<Number>();
list.add(42);
System.out.println("Lower bound recap: " + list);
}
}よくある質問
「下限付きワイルドカード」レッスンは無料ですか?
はい。「下限付きワイルドカード」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「下限付きワイルドカード」で何を学びますか?
消費側には ? super T を使います。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「下限付きワイルドカード」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 上限付きワイルドカード
- 下限付きワイルドカード
- PECS 原則
- API でのワイルドカード