1

(単純化するために)次のような問題がありました:

public void method(List<List<?>> list){...}

次のコマンドで呼び出すと、コンパイル エラーが発生しました。

method(new ArrayList<List<String>>()); // This line gives the error

同様のスレッドを読んだ後、メソッドのシグネチャを次のように書き直せばうまくいくことがわかりました。

public void method(List<? extends List<?>> list){...}

さて、私の質問は、なぜ次のように機能するのですか?

public <T> void method(List<List<T>> list){...}
4

3 に答える 3

5

マルチレベルのワイルドカード構文を扱う場合、混乱が生じます。これらのタイプが正確に何を意味するのかを理解しましょう。

  • List<List<?>>具体的なパラメータ化された型です。これは、さまざまなタイプの の異種コレクションList<E>です。List<?>のすべてのインスタンス化のファミリを表すため、実際には に を渡すことListはできません。メソッド内にa を追加することを止めるものは何もないため、コンパイラが許可していれば実行時にクラッシュします。ArrayList<List<String>>List<List<?>>List<Integer>

  • List<? extends List<?>>ワイルドカード パラメータ化されたタイプです。のさまざまなタイプのファミリを表しますList<E>。基本的には、、、などList<ArrayList<String>>ですList<LinkedList<Date>>。から拡張された任意のタイプのリストにすることができますList<?>。そのため、 a を渡しても安全ArrayList<List<String>>です。理由は、何も追加することはできませんがnull、リストに追加することはできません。リストに何かを追加すると、コンパイル時エラーになります。

  • に関してはList<List<T>>、これも具体的なパラメータ化された型です。また、現在ジェネリック メソッドを扱っているため、型パラメーターは渡された型であると推測されます。したがって、 の場合ArrayList<List<String>>、タイプTは として推論されTます。ジェネリック メソッドは、それで宣言された型を扱います。したがって、ここには単一のタイプしかありませんT。取得するすべてのリストは、List<List<T>>確かにList<T>for any type になりTます。つまり、そのタイプの同種のコレクションListです。メソッド内では、任意List<E>の型を に追加することはできませList<List<T>>ん。コンパイラは、その型Eが と互換性があるかどうかを認識していないためTです。だから、それは安全な呼び出しです。


関連している:

于 2013-10-28T19:46:06.517 に答える
1

基本的な理由は、List<List<?>>が のスーパークラスではないことですList<List<String>>

Aには、たとえばaと aをList<List<?>>含めることができます。List<Integer>List<String>

ジェネリック型は正確に一致する必要があります。そうしないと、誤った割り当てが行われる可能性があります。

于 2013-10-28T19:48:57.067 に答える