不兼容的通配符类型

时间:2013-11-01 13:08:43

标签: java generics wildcard unbounded-wildcard

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

采取以下方法:

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 ?>>

WTF? Map.entrySet()被指定为返回Set<Map.Entry<K, V>>类型的对象,因此在上面的示例中,myMap.entrySet()会返回Set<Map.Entry<?, ?>>。但它没有编译!

甚至更奇怪,从顶部的链接问题,将方法更改为此使得它编译:

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

WTF ??? entrySet上拨打Map<?, ?>会返回Set<Map.Entry<K, V>>,但无法分配给Set<Map.Entry<K, V>> Set<? extends Map.Entry<K, V>>类型的变量,但它可以是? extends ...类型的变量?????

任何人都可以了解这里发生的事情吗?这是否意味着,每当我使用至少2级深度的通配符类型编写方法时,我必须记得在某处将其设为{{1}}?

1 个答案:

答案 0 :(得分:6)

每个人?可以独立变化,因此无法保证<?,?>声明中的myMap<?,?>声明中的set匹配。

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

另一方面,Set<Map<String,Integer>> Map<String,Integer>的超类型,因为Map<?,?>myMap.entrySet()的子类型。因此,可以将Set<? extends Map<?,?>>分配给String类型的变量。

请注意,此处IntegermyMap没有什么特别之处,但<K, V> void method(Map<K, V> myMap) { Set<Map.Entry<K, V>> set = myMap.entrySet(); ... 必须是的地图!

你可以写

{{1}}