JavaGenerics–>vs<?オブジェクトを拡張>
1. 概要
このクイックチュートリアルでは、
ただし、これは高度なトピックであるため、問題の核心に飛び込む前に、主題の基本的な理解を取得することが不可欠です。
2. ジェネリック医薬品の背景
ジェネリックスは、実行時エラーを排除し、型の安全性を強化するためにJDK5に導入されました。 この追加の型安全性により、一部のユースケースでのキャストが不要になり、プログラマーが汎用アルゴリズムを記述できるようになります。どちらも、より読みやすいコードにつながる可能性があります。
たとえば、JDK 5より前では、キャストを使用してリストの要素を処理する必要がありました。 これにより、特定のクラスのランタイムエラーが発生しました。
List aList = new ArrayList();
aList.add(new Integer(1));
aList.add("a_string");
for (int i = 0; i < aList.size(); i++) {
Integer x = (Integer) aList.get(i);
}
さて、このコードには、対処したい2つの問題があります。
- aList から値を抽出するには、明示的なキャストが必要です–タイプは左側の変数タイプに依存します–この場合は Integer
- a_stringをIntegerにキャストしようとすると、2回目の反復でランタイムエラーが発生します。
ジェネリックは私たちの役割を果たします:
List<Integer> iList = new ArrayList<>();
iList.add(1);
iList.add("a_string"); // compile time error
for (int i = 0; i < iList.size(); i++) {
int x = iList.get(i);
}
コンパイラは、a_stringをIntegerタイプのListに追加することはできないことを通知します。これは、実行時に検出するよりも優れています。
さらに、コンパイラはiListがIntegerを保持していることをすでに知っているため、明示的なキャストは必要ありません。 さらに、開箱の魔法のおかげで、整数タイプも必要ありませんでした。そのプリミティブ形式で十分です。
3. Genericsのワイルドカード
疑問符、またはワイルドカードは、未知のタイプを表すためにジェネリックで使用されます。 それは3つの形式を持つことができます:
- 無制限のワイルドカード : リスト>不明なタイプのリストを表します
- アッパーバウンドワイルドカード :
リスト<? 番号を拡張> のリストを表します番号またはそのサブタイプなど整数とダブル - 下限のワイルドカード :
リスト<? 超整数> のリストを表します整数またはそのスーパータイプ番号と物体
さて、 Object はJavaのすべてのタイプに固有のスーパータイプであるため、未知のタイプを表すこともできると考えたくなるでしょう。 言い換えると、 リスト>とリスト同じ目的を果たすことができます。 しかし、そうではありません。
これらの2つの方法を考えてみましょう。
public static void printListObject(List<Object> list) {
for (Object element : list) {
System.out.print(element + " ");
}
}
public static void printListWildCard(List<?> list) {
for (Object element: list) {
System.out.print(element + " ");
}
}
Integer のリストが与えられた場合、次のように言います。
List<Integer> li = Arrays.asList(1, 2, 3);
printListObject(li)はコンパイルされず、次のエラーが発生します。
The method printListObject(List<Object>) is not applicable for the arguments (List<Integer>)
一方、 printListWildCard(li)はコンパイルされ、 1 23をコンソールに出力します。
4. >と <? オブジェクトを拡張> –類似点
上記の例で、printListWildCardのメソッドシグネチャを次のように変更した場合。
public static void printListWildCard(List<? extends Object> list)
それはと同じように機能します printListWildCard(リスト>リスト) やりました。 これは、 Object がすべてのJavaオブジェクトのスーパータイプであり、基本的にすべてがObjectを拡張するという事実によるものです。 したがって、IntegerのListも処理されます。
要するに、
ほとんどの場合、それは当てはまりますが、ですが、いくつかの違いもあります。 次のセクションでそれらを見てみましょう。
5. >と <? オブジェクトを拡張> – 違い
Reizable タイプは、コンパイル時にタイプが消去されないタイプです。 つまり、再利用不可能な型の実行時表現は、一部が消去されるため、コンパイル時の表現よりも情報が少なくなります。
原則として、パラメーター化されたタイプは再作成できません。 これの意味はリスト
このルールの唯一の例外は、無制限のワイルドカードタイプです。 これはリストを意味します>と地図,?>再利用可能です 。
一方で、
再利用不可能な型は、 instanceof 演算子や配列の要素など、特定の状況では使用できません。
したがって、次のように記述します。
List someList = new ArrayList<>();
boolean instanceTest = someList instanceof List<?>
このコードはコンパイルされ、instanceTestはtrueです。
しかし、私たちが使用する場合 instanceof 上の演算子
List anotherList = new ArrayList<>();
boolean instanceTest = anotherList instanceof List<? extends Object>;
その場合、2行目はコンパイルされません。
同様に、以下のスニペットでは、1行目はコンパイルされますが、2行目はコンパイルされません。
List<?>[] arrayOfList = new List<?>[1];
List<? extends Object>[] arrayOfAnotherList = new List<? extends Object>[1]
6. 結論
この短いチュートリアルでは、> と
ほとんど同じですが、再利用可能かどうかという点で2つの間に微妙な違いがあります。