この問題は、次の古い Apache スレッドで対処されています。
問題は、メソッドが型と互換性のない をentrySet()
返している
ことです。and の部分を削除すると、その理由を簡単に説明できます。したがって、 と があります。Set<Map.Entry<capture-of ? extends K, capture-of ? extends V>>
Set<Map.Entry<? extends K, ? extends V>>
extends K
extends V
Set<Map.Entry<?, ?>
Set<Map.Entry<capture-of ?, capture-of ?>>
最初のものSet<Map.Entry<?, ?>>
は、さまざまなタイプの Map.Entries のセットです。つまり、異種のコレクションです。Map.Entry<Long, Date>
aと aMap.Entry<String, ResultSet>>
およびその他のタイプのペアをすべて同じセットに含めることができます
。
一方、Set<Map.Entry<capture-of ?, capture-of ?>>
は同じ (ただし不明な) 型のペアの同種のコレクションです。たとえば、 である可能性がある
Set<Map.Entry<Long, Date>>
ため、セット内のすべてのエントリは である必要があります
Map.Entry<Long, Date>
。
問題の核心は、最上位のワイルドカードが をキャプチャすることです。つまり、それらは本質的に 1 回限りの型パラメーターです。対照的に、ネストされたワイルドカードはキャプチャされず、多少異なる意味を持ちます。
したがって、単純化のために境界を取り除き、次のように宣言します。
Map<?, ?> m;
「特定の未知のタイプのキーと特定の未知のタイプの値のマップ」を意味します。
しかし、宣言する
Set<Map.Entry<?, ?>> s;
「任意のタイプのキーと値のエントリのセット」を意味します。
式がそれを返すのではなく、「特定の未知のタイプのキーと特定のm.entrySet()
未知のタイプの値のエントリのセット」を返したくないため、ここで問題が発生します。ジェネリックは共変ではないため、これらの型は互換性がありません: Aは a ではありません。Set<Type>
Set<SuperType>
(ネストされたワイルドカードのニュアンスを理解するのに役立つこの魅力的な投稿を参照してください。ジェネリック メソッドの複数のワイルドカードにより、Java コンパイラ (および私!) は非常に混乱します。)
1 つの回避策は、正式な型パラメーターを入れ子にすることができるという事実を利用するキャプチャ ヘルパーメソッドを使用することです。
private <K extends String, V extends Integer> void help(final Map<K, V> map) {
final Set<Map.Entry<K, V>> entries = map.entrySet();
// logic
}
...
Map<? extends String, ? extends Integer> m = null;
help(m);
String
とInteger
は bothであるため、これは不自然な例ですfinal
が、概念を示しています。
より簡単な回避策は次のとおりです。
Set<? extends Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();
これは、非null
要素を に追加することs
は許可されていないことを意味しますが、Set
返された byの場合entrySet
、add
およびメソッドはとにかくサポートされていません (この点addAll
を明確にしてくれたことに newacct に感謝します)。