143

OracleDocGenericMethod の汎用メソッドについて読んでいます。いつワイルドカードを使用し、いつジェネリックメソッドを使用するかという比較について、私はかなり混乱しています。資料より引用。

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

代わりに、ここでジェネリック メソッドを使用することもできます。

interface Collection<E> {
    public <T> boolean containsAll(Collection<T> c);
    public <T extends E> boolean addAll(Collection<T> c);
    // Hey, type variables can have bounds too!
}

[…] これは、型引数がポリモーフィズムに使用されていることを示しています。その唯一の効果は、さまざまな呼び出しサイトでさまざまな実引数の型を使用できるようにすることです。その場合は、ワイルドカードを使用する必要があります。ワイルドカードは柔軟なサブタイピングをサポートするように設計されており、それをここで表現しようとしています。

(Collection<? extends E> c);ワイルドカードライクも一種のポリモーフィズムをサポートしていると思いませんか? では、なぜジェネリック メソッドの使用がこれで良くないと見なされるのでしょうか。

続けて、次のように述べています。

ジェネリック メソッドを使用すると、型パラメーターを使用して、メソッドへの 1 つまたは複数の引数の型とその戻り値の型の間の依存関係を表現できます。そのような依存関係がない場合は、ジェネリック メソッドを使用しないでください。

これは何を意味するのでしょうか?

彼らはその例を提示しました

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

[…]

ワイルドカードをまったく使用せずに、このメソッドの署名を別の方法で記述することもできます。

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

ドキュメントは 2 番目の宣言を思いとどまらせ、最初の構文の使用を促進しますか? 最初の宣言と 2 番目の宣言の違いは何ですか? どちらも同じことをしているように見えますか?

誰かがこの領域に光を当てることができますか.

4

9 に答える 9

12

最初の質問では、パラメーターの型とメソッドの戻り値の型の間に関係がある場合は、ジェネリックを使用することを意味します。

例えば:

public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);

ここでは、特定の基準に従って T の一部を抽出しています。T の場合Long、メソッドはLongandを返しCollection<Long>ます。実際の戻り値の型はパラメーターの型に依存するため、ジェネリック型を使用することをお勧めします。

そうでない場合は、ワイルド カード タイプを使用できます。

public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);

この 2 つの例では、コレクション内の項目の型が何であれ、戻り値の型は と にintなりbooleanます。

あなたの例では:

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);
}

これら 2 つの関数は、コレクション内のアイテムのタイプが何であれ、ブール値を返します。2 番目のケースでは、E のサブクラスのインスタンスに限定されます。

2 番目の質問:

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...
}

この最初のコードでは、異種List<? extends T> srcをパラメーターとして渡すことができます。このリストには、すべて基本クラス T を拡張する限り、異なるクラスの複数の要素を含めることができます。

あなたが持っていた場合:

interface Fruit{}

class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}

あなたができる

List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>(); 

Collections.copy(fridge, basket);// works 

一方で

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...
}

T のサブクラスList<S> srcである 1 つの特定のクラス S である必要があります。リストには、1 つのクラス (このインスタンスでは S) の要素のみを含めることができ、T も実装している場合でも、他のクラスを含めることはできません。前の例を使用することはできませんが、次のようにすることができます。

List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();

Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */
于 2013-08-11T21:21:48.727 に答える
3

私はあなたの質問に一つずつ答えようとします。

(Collection<? extends E> c);ワイルドカードライクも一種のポリモーフィズムをサポートしていると思いませんか?

いいえ。その理由は、限定されたワイルドカードに定義済みのパラメーター タイプがないからです。不明です。それが「知っている」のは、「包含」がタイプE(定義されているものは何でも)であることだけです。したがって、提供された値が制限された型と一致するかどうかを検証および正当化することはできません。

したがって、ワイルドカードでポリモーフィックな動作を行うことは賢明ではありません。

ドキュメントは 2 番目の宣言を思いとどまらせ、最初の構文の使用を促進しますか? 最初の宣言と 2 番目の宣言の違いは何ですか? どちらも同じことをしているように見えますか?

この場合、最初のオプションはT常に制限されsourceており、サブクラスの (未知数の) 値を確実に持つため、より優れていますT

したがって、数字のすべてのリストをコピーしたい場合、最初のオプションは次のようになります

Collections.copy(List<Number> dest, List<? extends Number> src);

srcにあるパラメータ化された型には上限があるため、基本的に、、などList<Double>を受け入れることができます。List<Float>dest

S2 番目のオプションでは、コピーするすべてのタイプを強制的にバインドします。

//For double 
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.

//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.

バインドSが必要なパラメーター化された型です。

これが役立つことを願っています。

于 2013-08-11T21:26:56.970 に答える