16

最後の質問で (答えてくれてありがとう)、 と の違いを学びましList<Object>List<?>

ただし、ワイルドカードの有用性はまだわかりません。

私は2つArrayListのsを持っています:

ArrayList<Integer> li = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList<String> ls = new ArrayList<String>(Arrays.asList("one","two","three"));

次に、以下の 2 つのコード ブロックを見てください。

static void printList(ArrayList<?> list) 
{
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

static <T> void printList(ArrayList<T> list) 
{
    for (T elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

私が電話するとき:

printList(li);
printList(ls);

どちらのメソッドも出力を返します。

1 2 3
one two three

ただし、for ループの 2 番目の解決策では、Objects の代わりにパラメータ化された型を使用します (はるかにエレガントだと思います)。

したがって、主な疑問は残ります:なぜワイルドカードが必要なのですか?

4

8 に答える 8

11

質問が「ワイルドカードの有用性」である場合:

ワイルドカードは、型パラメーターに関する部分的な知識のみが必要な場合に役立ちます。「部分的な知識」は、上限と下限によって実装されます (? super T または ? extends T)。バインドされていないワイルドカード ( ? ) のみを使用すると、知識がまったくないことを意味し、ワイルドカードが実際に役立つ場所がわかりません。

ワイルドカードは、メソッド パラメータの型、戻り値の型、および例外の型の間の関係を作成するために、型パラメータとの組み合わせで使用できます。したがって、有用なワイルドカードの例は次のとおりです。

 class ListManager<T> {
    public void add(T item, List<? super T> list) {
        [... some useful operation ...]
         list.add(item);
    }
}

public class Main {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<Object>();
        Integer item = 10;
        ListManager<Integer> manager = new ListManager<Integer>();
        manager.add(item, list);
    }
}

メソッド「ListManager.add()」は、「リスト」のタイプと「アイテム」のタイプの関係を作成します。「リスト」の操作は常にタイプ セーフですが、異なるパラメーター タイプのリストでメソッド「add」を使用できます。パラメーター「リスト」に最小の制約を使用しました。

( jls7 のドキュメントも参照してください)

于 2012-09-10T11:36:03.753 に答える
7

Javaジェネリックチュートリアルでは、次のように述べています。

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

c の要素の型が何を表しているのかわからないので、それにオブジェクトを追加することはできません。add() メソッドは、コレクションの要素型である E 型の引数を取ります。実際の型パラメーターが ? の場合、不明な型を表します。追加するために渡すパラメーターは、この未知の型のサブタイプでなければなりません。型がわからないので、何も渡すことができません。唯一の例外は、すべての型のメンバーである null です。

一方、List を指定すると、get() を呼び出して結果を利用できます。結果の型は未知の型ですが、オブジェクトであることは常にわかっています。したがって、get() の結果を Object 型の変数に代入するか、Object 型が予期されるパラメーターとして渡すことは安全です。

したがって、ワイルドカード型を使用するadd()と、例外を除いてリストにアクセスできなくなりますnull。リストを呼び出しget()ているだけなら、それが少なくともオブジェクトであることがわかります。

于 2012-09-10T09:34:10.907 に答える
5

Item 28-USE BOUNDED WILDCARDS TO INCREASE API FLEXIBILITY of effective javaによると

型パラメーターがメソッド宣言で 1 回だけ出現する場合は、ワイルドカードに置き換えます。

于 2012-09-10T11:41:13.800 に答える
4

このクラス階層があるとしましょう:

Fruit
Apple extends Fruit
Orange extends Fruit

...そして各種類の果物のリスト:

List<Apple> apples ;List<Orange> oranges ;

ここListで、これらのリストのいずれかを参照できる が必要です。

だからあなたは宣言しますList<? extends Fruit> fruits ;

ここでは型変数を使用できません。

于 2012-09-10T09:43:35.890 に答える
2

あなたが正しい。技術的には、パラメーターの型の最初のレベルにワイルドカードが表示されるたびに、その型変数に新しい型変数を作成し、その型変数をそのワイルドカードの代わりに使用できます。これは同じように機能します。

ただし、ワイルドカードを使用するよりもはるかにエレガントではないと私は主張します。型変数は、同じ型変数を持つ2つのパラメーターがある場合や、パラメーターと戻り型の間のように、異なる式の間で制約を確立することを表現するのに役立ちます。パラメータ内の1つの場所でのみ使用される型変数は、一種の無駄であり、ワイルドカードの意味とまったく同じであり、他の場所では必要とされない「匿名」型変数です。他の何かで制約する必要なしに、「ある型」を表現する必要がある場合、なぜボーナス型変数でメソッドシグネチャを乱雑にするのでしょうか。

型変数を置き換えることができないワイルドカードの他の使用法もあります。たとえば、メソッドについて考えてみpublic List<?> foo()ます。それはある種のリストを返しますが、あなたは何のリストを知りません(そしてそれに何かを追加することは安全ではありません)。ワイルドカードなしで型変数を使用してそれを表現する方法はありません。

また、ネストされた型パラメーターのワイルドカードを検討してください。型の変数List<List<?>>、つまり、要素がさまざまなもののリストである可能性のある異種リストを持つことができます。これもワイルドカードを使用せずに表現することはできません。

于 2012-09-10T22:26:50.457 に答える
2

ワイルドカードを使用すると、コードはタイプ セーフになります。の

List myList;

任意のオブジェクトを追加できます。しかし、次の場合:

List<?> myList;

nullのみを追加できます。

クラス (List.class) が必要な場合、またはタイプ (List のインスタンス) を確認する必要がある場合にのみ、型パラメーターなしで List を使用する必要があります。

于 2012-09-10T09:30:13.887 に答える
1

私が見つけたワイルドカードの最適な用途の 1 つは、ジェネリック型の複雑な入れ子です。

Pair<T,E> のリストを使用した簡単な例です。ワイルドカードを使用すると、コードが短くなり、読みやすくなります。これは、私がブール値だけに関心があることがわかるからです。

  ArrayList<Pair<Boolean, OneOrOtherLongClassName>> pairList = ...;
  for(Pair<Boolean,?> p:pairList)
  {
      if(p.first)count++;
  }
于 2012-09-13T13:26:39.677 に答える
1

なぜなら

次の場合にリストを変更できます<T> list.add((T) new Object());

?ただし、リストが変更されないことが保証される場合、リストを変更することはできません。null 以外のものを追加すると、コンパイラはエラーを生成します。

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

c の要素型が何を表しているのかわからないため、オブジェクトを追加することはできません。add() メソッドは、コレクションの要素型である E 型の引数を取ります。実際の型パラメーターが ? の場合、不明な型を表します。追加するために渡すパラメーターは、この未知の型のサブタイプでなければなりません。型がわからないので、何も渡すことができません。唯一の例外は、すべての型のメンバーである null です。

一方、 が与えられた場合、結果List<?>を呼び出しget()て利用することができます。結果の型は未知の型ですが、オブジェクトであることは常にわかっています。したがって、get() の結果を Object 型の変数に代入するか、Object 型が予期されるパラメーターとして渡すことは安全です。

ワイルドカードの詳細

于 2012-09-10T09:31:25.950 に答える