2013-02-28 14 views
6

私はジェネリックスを読んでコンセプトに慣れ親しんでいました。特に、ワイルドカードを使用することはほとんどありませんでした。私が読んだことから、ワイルドカードを使う理由を理解できません。私が続けている例の1つは次のとおりです。Javaジェネリックス:ワイルドカード

void printCollection(Collection<?> c) { 
    for (Object o : c){ 
    System.out.println(o); 
    } 
} 

なぜあなたは書きません。このように:

<T> void printCollection(Collection<T> c) { 
    for(T o : c) { 
     System.out.println(o); 
    } 
} 

OracleのWebサイトから別の例:これはなぜ

public static <T extends Number> double sumOfList(List<T> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

アムのように書かれていません

public static double sumOfList(List<? extends Number> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

私は何かを欠いている?

+0

可能です[複製](http://stackoverflow.com/questions/10943137/difference-between-generic-type-and-wildcard-type) – Jayamohan

+1

@Jayamohan私は同意しません。 –

答えて

3

:されて生じた

一つは、質問:私は、一般的なメソッドを使用する必要があり、私は、ワイルドカードタイプを使用する必要がありますか?答えを理解するために、Collectionライブラリのいくつかのメソッドを調べてみましょう。

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! 
} 

をしかし、のcontainsAllとのaddAllの両方で、型パラメータTは、一度だけ使用されます。戻り値の型は、型パラメーターに依存せず、メソッドの他の引数もありません(この場合、引数は1つだけです)。これは、多型に型引数が使用されていることを示しています。その唯一の効果は、さまざまな実際の引数型をさまざまな呼び出しサイトで使用できるようにすることです。そのような場合は、ワイルドカードを使用する必要があります。ワイルドカードは、ここで表現しようとしている柔軟なサブタイプ化をサポートするように設計されています。

最初の例では、操作は型に依存しないためです。

第2の理由は、Numberクラスのみに依存するからです。

+0

ありがとう、すべての説明は良いものでしたが、何らかの理由でこれが私を最もよく理解するのに役立ちました。 –

3

なぜ物事は必要以上に複雑になるのですか?例はthe simplest thing that could possibly workを示しています。これらの例は一般的な方法を説明しようとしていません。オブジェクトを受け入れることができ

<T> void printCollection(Collection<T> c) { 
    for(T o : c) { 
     System.out.println(o); 
    } 
} 

System.out.println()ので、そう何よりも、特定が必要とされている:

なぜとしてこれを書いていないでしょう。あなたはすべての異なるT extends Numberに異なるパラメータを必要としないので、

は、なぜこれが、再び

public static <T extends Number> double sumOfList(List<T> list) { 
    double s = 0.0; 
    for (Number n : list) 
     s += n.doubleValue(); 
    return s; 
} 

として書かれていません。 List<? extends Number>を受け入れる非ジェネリックな方法で十分です。

+0

私はちょうど2つの違いを誤解しているかもしれないと思いますか、それとも同じですか?私がこれまでにどんな状況になっているのではなく、Tを使って解決することができますか?私はワイルドカードのポイントを完全に見逃していると感じています。 –

+2

@JonTaylor: '?'ではなく 'T'で解決できない状況はまったくありませんが、'? 'は名前が必要ではなく、あなたが本当に気にしないタイプは何ですか? –

+0

@LouisWasserman 'Class 'を返す 'Class.forName'は、ワイルドカードだけが適切である例かもしれません。 –

3

メソッドのパラメータ型に上限がある第1レベルのワイルドカードがある場合は、型パラメータで置き換えることができます。

カウンタ例(ワイルドカードはタイプパラメータで置き換えることができない)ことが一般的と考えられる

 void foo1(List<?> arg) 

    <T> void foo2(List<T> arg) 

いずれかのワイルドカードまたはタイプパラメータによって解決することができる場合について今

List<?> foo() // wildcard in return type 

    void foo(List<List<?>> arg) // deeper level of wildcard 

    void foo(List<? super Number> arg) // wildcard with lower bound 

foo1()foo2()よりもスタイリッシュです。おそらく少し主観的です。私は個人的にはfoo1()の署名が分かりやすいと思います。そして、foo1()が業界で圧倒的に採用されているので、この大会に従う方がよいでしょう。

foo1()は、arg.add(something)foo1()で簡単に処理できないため、少し抽象的に扱います。もちろん、簡単に回避することができます(つまり、argをfoo2()に渡してください)。パブリックメソッドがfoo1()のように見え、内部的にプライベートfoo2()に転送することも一般的な方法です。

あり、ワイルドカードはしないだろう例もあり、型パラメータが必要とされている:

<T> void foo(List<T> foo1, List<T> foo2); // can't use 2 wildcards. 

この議論は、これまでは、メソッドシグネチャについてです。他の場所では、型パラメーターを導入できない場合、ワイルドカードは不可欠です。 Oracleから

+0

+1型パラメータは[下限を持つことはできません](http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword)。 –

関連する問題