JRR*_*JRR 3 java generics bounded-wildcard
我想知道这段代码有什么问题:
Map <? extends String, ? extends Integer> m = null;
Set<Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();
Run Code Online (Sandbox Code Playgroud)
编译器抱怨错误消息:
类型不匹配:无法转换
Set<Map.Entry<capture#1-of ? extends String,capture#2-of ? extends Integer>>为Set<Map.Entry<? extends String,? extends Integer>>
应该是什么类型的s?Eclipse建议,Set<?>但我想尝试更具体.
这个旧的Apache线程解决了这个问题:
问题是该
entrySet()方法返回aSet<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集合 - 即它是异构集合.它可以包含aMap.Entry<Long, Date>和aMap.Entry<String, ResultSet>>以及任何其他类型的对,都在同一组中.另一方面,
Set<Map.Entry<capture-of ?, capture-of ?>>是同一类(虽然未知)类型的同源集合.例如,它可能是aSet<Map.Entry<Long, Date>>,因此集合中的所有条目必须是Map.Entry<Long, Date>.
问题的关键在于顶层通配符捕获,这意味着它们本质上是一次性类型参数.相比之下,嵌套通配符不会捕获,并且具有某种不同的含义.
因此,为了简单起见,删除界限,声明
Map<?, ?> m;
Run Code Online (Sandbox Code Playgroud)
表示"某些特定未知类型的键和某些特定未知类型的值的映射".
但是宣告
Set<Map.Entry<?, ?>> s;
Run Code Online (Sandbox Code Playgroud)
表示"任何类型的键和值的一组条目".
所以这就是你遇到麻烦的地方,因为表达式m.entrySet()不想返回它,而是"一些特定未知类型的键和一些特定未知类型的值的一组条目".这些类型是不兼容的,因为泛型不是协变的:A Set<Type>不是Set<SuperType>.
(请参阅这篇引人入胜的帖子,它有助于梳理嵌套通配符的细微差别:泛型方法上的多个通配符使Java编译器(和我!)非常混淆.)
一种解决方法是使用捕获帮助器方法,该方法利用了可以嵌套正式类型参数的事实:
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);
Run Code Online (Sandbox Code Playgroud)
这是一个人为的例子,String并且Integer都是final,但它显示了这个概念.
一个更简单的解决方法如下:
Set<? extends Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();
Run Code Online (Sandbox Code Playgroud)
这意味着将不null元素s是不允许的,但在的情况下Set通过返回entrySet时,add和addAll方法是不支持的反正(感谢newacct为澄清这一点).
| 归档时间: |
|
| 查看次数: |
1246 次 |
| 最近记录: |