不兼容的通配符类型

the*_*oop 3 java generics wildcard unbounded-wildcard

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

采取以下方法:

void method(Map<?, ?> myMap) {
    Set<Map.Entry<?, ?>> set = myMap.entrySet();
    ...
}
Run Code Online (Sandbox Code Playgroud)

简单,不是吗?但是,这无法在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 ?>>
Run Code Online (Sandbox Code Playgroud)

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

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

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

跆拳道??? 呼叫entrySet上的Map<?, ?>回报Set<Map.Entry<K, V>>,这是不能被分配给类型的变量Set<Map.Entry<K, V>>,但它可以以类型的变量Set<? extends Map.Entry<K, V>>?????

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

Daw*_*ica 6

每个人?可以独立地变化,所以有没有保证,<?,?>声明中的myMap比赛的<?,?>中的声明set.

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

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

请注意,有没有什么特别的String,并Integer在这里,但myMap必须是地图上的东西!

你可以写

<K, V> void method(Map<K, V> myMap) {
    Set<Map.Entry<K, V>> set = myMap.entrySet();
    ...
Run Code Online (Sandbox Code Playgroud)