3

这个问题之后,它提供了一个解决方案但没有解释它(不幸的是,答案中的链接现在已经死了):

采取以下方法:

void method(Map<?, ?> myMap) {
    Set<Map.Entry<?, ?>> set = myMap.entrySet();
    ...
}

很简单,不是吗?但是,这无法在 jdk1.7.0_25 上编译:

incompatible types
required: java.util.Set<java.util.Map.Entry<?,?>>
found:    java.util.Set<java.util.Map.Entry<capture#1 of ?,capture#2 of ?>>

怎么回事?Map.entrySet()被指定为返回一个 类型的对象Set<Map.Entry<K, V>>,所以在上面的例子中,myMap.entrySet()返回一个Set<Map.Entry<?, ?>>. 但它不编译!

更奇怪的是,从顶部的链接问题中,将方法更改为此使其编译:

void method(Map<?, ?> myMap) {
    Set<? extends Map.Entry<?, ?>> set = myMap.entrySet();
    ...
}

怎么回事???调用entrySetaMap<?, ?>返回 aSet<Map.Entry<K, V>>,它不能分配给 type 的变量Set<Map.Entry<K, V>>,但Set<? extends Map.Entry<K, V>>?????

谁能解释这里发生了什么?这是否意味着,每当我使用至少 2 层深度的通配符类型编写方法时,我必须记住在? extends ...某个地方创建它?

4

1 回答 1

6

每一个?可以独立变化,因此不能保证声明中的 与<?,?>声明中的myMap匹配。<?,?>set

这意味着一旦我有了一个Set<Map<?,?>>,我可以将任何类型的Map放入该集合中,因为Map<?,?>它是所有类型的超类型Map。但这不是Set<Map<String,Integer>>(例如)具有的属性-就我可以放入的地图类型而言,它的限制要大得多。所以Set<Map<?,?>>不是Set<Map<String,Integer>>. 但myMap.entrySet()很容易成为 a Set<Map<String,Integer>>,具体取决于是什么myMap。所以编译器必须禁止我们将它分配给 type 的变量Set<Map<?,?>>,这就是正在发生的事情。

另一方面,Set<? extends Map<?,?>> 的超类型Set<Map<String,Integer>>,因为Map<String,Integer>是 的子类型Map<?,?>。所以可以赋值myMap.entrySet()给 type 的变量Set<? extends Map<?,?>>

请注意,这里没有什么特别之处StringIntegermyMap必须是某物的地图!

你可以写

<K, V> void method(Map<K, V> myMap) {
    Set<Map.Entry<K, V>> set = myMap.entrySet();
    ...
于 2013-11-01T13:13:08.597 回答