1. 概要

このクイックチュートリアルでは、 の類似点と相違点>および<? JavaGenericsでObject>を拡張します

ただし、これは高度なトピックであるため、問題の核心に飛び込む前に、主題の基本的な理解を取得することが不可欠です。

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_stringIntegerにキャストしようとすると、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_stringIntegerタイプのListに追加することはできないことを通知します。これは、実行時に検出するよりも優れています。

さらに、コンパイラはiListIntegerを保持していることをすでに知っているため、明示的なキャストは必要ありません。 さらに、開箱の魔法のおかげで、整数タイプも必要ありませんでした。そのプリミティブ形式で十分です。

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を拡張するという事実によるものです。 したがって、IntegerListも処理されます。

要するに、 だということだ ? と ? この例では、extendsObjectは同義語です。

ほとんどの場合、それは当てはまりますが、ですが、いくつかの違いもあります。 次のセクションでそれらを見てみましょう。

5. > <? オブジェクトを拡張> – 違い

Reizable タイプは、コンパイル時にタイプが消去されないタイプです。 つまり、再利用不可能な型の実行時表現は、一部が消去されるため、コンパイル時の表現よりも情報が少なくなります。

原則として、パラメーター化されたタイプは再作成できません。 これの意味はリスト地図再利用可能ではありません。 コンパイラはそれらの型を消去し、それぞれListおよびMapとして扱います。

このルールの唯一の例外は、無制限のワイルドカードタイプです。 これはリストを意味します>と地図,?>再利用可能です

一方で、 リスト<? オブジェクトを拡張します>は再作成できません 。 微妙ですが、これは顕著な違いです。

再利用不可能な型は、 instanceof 演算子や配列の要素など、特定の状況では使用できません。

したがって、次のように記述します。

List someList = new ArrayList<>();
boolean instanceTest = someList instanceof List<?>

このコードはコンパイルされ、instanceTesttrueです。

しかし、私たちが使用する場合 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つの間に微妙な違いがあります。