2012-07-16 11 views
5

私はJava Generics documentationを見て、コードのこの部分を発見された、Javaのジェネリックキャプチャリスト<?>

public class WildcardError { 

void foo(List<?> l) { 
    //This give a compile time error 
    l.set(0,l.get(0)); 
} 
} 

私たちはList<?>から要素を取得し、別のList<?>に設定しようとしていることを理解することができます。コンパイラはエラーを出します。私の質問は、2つのリストが異なる場合、つまりl.set(0, m.get(0))ここではlmのリストが異なる場合に意味があります。しかし、上記の例では、llは同じリストです。なぜコンパイラーはそれを見るほどスマートではないのですか?それを実装するのは難しいですか?

編集: 私はヘルパーメソッドによって、または?の代わりにTを使用して、それを修正できることを承知しています。なぜコンパイラが私のためにそれをしないのだろうかと思っています。

答えて

4

コンパイラは、2つの式(この場合はll)が同じリストを参照するかどうかを判断する方法がないため、エラーを報告します。

やや一般化関連、質問:

public class WildcardError { 
    <T> void foo(List<T> l) { 
     // This will work 
     l.set(0, l.get(0)); 
    } 
} 

それとも、したくない場合:あなたの特定のケースで

+0

私は長い間、正式な理由について不思議でした。私は個人的には、これはJLSの機能が欠けていると感じています。両方のワイルドカードが正式に同じであるためです。直感では...しかしおそらく、より複雑なコードでは、 "同一の"ワイルドカードを認識するのが難しくなる –

+0

ええ。おそらく、スペックをかなり複雑にする興味深いコーナーケースがあります。良い質問。これは、この質問の一般化のようなものです。フォローアップとして投稿する必要があります。 – aioobe

+1

これは問題です:http://stackoverflow.com/questions/11500385/how-does-the-jls-justify-that-wildcards-cannot-be-formally-used-within-methods –

9

、明示的にこの問題を解決することができ元のAPIを変更し、デリゲートヘルパーメソッドを導入します。

public class WildcardError { 
    void foo(List<?> l) { 
     foo0(l); 
    } 

    private <T> void foo0(List<T> l) { 
     // This will work 
     l.set(0, l.get(0)); 
    } 
} 

残念ながら、コンパイラは「明らかな」<T>タイプを推論することはできません。私はそれについても疑問に思いました。すべてのワイルドカードが未知の<T>タイプに非形式的に変換される可能性があるので、コンパイラで改善できるもののようです。おそらく、これが省略された理由がいくつかありますが、これは直感的なものかもしれませんが、正式には不可能です。

UPDATE:私はちょうどCollections.swap()のこの独特の実装を見てきました

注:

public static void swap(List<?> list, int i, int j) { 
    final List l = list; 
    l.set(i, l.set(j, l.get(i))); 
} 

JDKの連中は、局所的に、これを処理するために、生のタイプに頼ります。これは、これはおそらくコンパイラによってサポートされる必要があることを示す強力なステートメントですが、ちょうど行われていなかったいくつかの理由(正式にこれを指定するには時間が例えば不足)のため

+1

はい私はこれを解決するための他の選択肢について認識しています。なぜ両方のリストが同じでも、コンパイラがそれを自分で行うことができないのだろうかと思うだけです。 –

+1

はい、私はそれについても疑問に思っています。過去に何百もの無駄な委任方法を書いていたのですが... - /あなたの質問を更新し、[JLS](http://docs.oracle.com/ javase/specs/jls/se7/html/index.html)、これについて説明しています。 –

+0

投稿を編集していただきありがとうございます:)どこでJLSに相談するのですか? –

2

List<?>は、いくつかの未知の要素を含むリストを意味し、と入力してください。list.get(i)を使用して要素を取得する場合は、のオブジェクトが返されますので、有効な推定値はObjectとなります。その後、list.set(index, list.get(index))を使用して要素を戻そうとすると、上記のようにList<?>にはというタイプが含まれている可能性があるので、コンパイル時エラーが発生するため、にClassCastExceptionが入る可能性があります。これはジョシュア・ブロックの効果的なJavaの第2版では非常によく説明されて

、項目28:使用してこれはまたPECS原則と良い説明として知られているAPIの柔軟性

を高めるためにワイルドカードを囲まれたが、この中に見つけることができますQ/A: What is PECS (Producer Extends Consumer Super)?List<?>はマイナーの例外を除いてList<? extends Object>と同じであることに注意してください)

分かりやすく用語で、1要素を取得するだけにメソッドのパラメータとしてList<?>を使用する必要がありますその方法の中から、それがの要素をのリストに入れる必要があるときではなく、 を入力して取得する必要がある場合は、を入力してください.Lukas Ederの答え(タイプセーフな方法)のようにタイプパラメータTを使用してメソッドを生成するか、単にList<Object>(タイプセーフな方法ではありません)を使用する必要があります。

関連する問題