不兼容的通配符类型应该兼容 [英] Incompatible wildcard types that should be compatible

查看:164
本文介绍了不兼容的通配符类型应该兼容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

采取以下方法:

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

简单,没有?但是,在jdk1.7.0_25上无法编译:


 不兼容类型
必需: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方法(Map<?,?> myMap){
Set< ;?扩展Map.Entry<?,?>> set = myMap.entrySet();
...
}

WTF ??在 Map<?,?> 上调用 entrySet 返回一个 Set< Map.Entry< K,V>> ,它不能被分配给类型的变量Set< Map.Entry< K,V> ;> ,但它可以转换为 Set <?扩展Map.Entry< K,V>> ?????



任何人都可以点亮这里发生的事情吗?这是否意味着,每当我使用至少2级深的通配符类型编写一个方法时,我必须记住要使它<?扩展... 某处?

解决方案

可以独立变化,因此不能保证 myMap 声明中的<?,?> <?,?> 集合的声明中。



这意味着,一旦我有一个 Set< Map<>>>>< / code>,我可以将任何类型 Map 到该集合中,因为 Map <?,?>> 是所有<$ c类型的超类型$ C>地图。但是这不是一个 Set< Map< String,Integer>> (例如)的属性 - 它对我可以放置什么类型的地图进去。因此, Set< Map <?,?>>> 不是超类型 Set< Map< String,Integer>> 。但 myMap.entrySet()很容易就是 Set< Map< String,Integer>> ,这取决于什么 myMap 是。所以编译器必须禁止我们将它分配给 Set< Map<>>>>< / code>类型的变量,这就是发生了什么。



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



请注意, String Integer 在这里,但是 myMap 必须是的地图!



您可以写下:

 < K,V> void方法(Map< K,V> myMap){
Set< Map.Entry< K,V>> set = myMap.entrySet();
...


Following on from this question, which provides a solution but doesn't explain it (unfortunately, the links in the answers are now dead):

Take the following method:

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

Simple, no? However, this fails to compile on 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() is specified as returning an object of type Set<Map.Entry<K, V>>, so in the example above, myMap.entrySet() returns a Set<Map.Entry<?, ?>>. But it doesn't compile!

Even weirder, from the linked question at the top, changing the method to this makes it compile:

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

WTF??? Calling entrySet on a Map<?, ?> returns a Set<Map.Entry<K, V>>, which can't be assigned to a variable of type Set<Map.Entry<K, V>>, but it can to a variable of type Set<? extends Map.Entry<K, V>>?????

Can anyone shed light on what's going on here? And does this mean that, whenever I write a method using a wildcard type at least 2 levels deep, I have to remember to make it ? extends ... somewhere?

解决方案

Each of those ? can vary independently, so there's no guarantee that the <?,?> in the declaration of myMap matches the <?,?> in the declaration of set.

What this means is that once I have a Set<Map<?,?>>, I can put any type of Map into that set, because Map<?,?> is a supertype of all types of Map. But this is not a property that Set<Map<String,Integer>> (for example) has - it's far more restrictive in terms of what types of map I can put into it. So Set<Map<?,?>> is not a supertype of Set<Map<String,Integer>>. But myMap.entrySet() could easily be a Set<Map<String,Integer>>, depending on what myMap is. So the compiler has to forbid us from assigning it to a variable of type Set<Map<?,?>>, and that's what's happening.

On the other hand, Set<? extends Map<?,?>> is a supertype of Set<Map<String,Integer>>, because Map<String,Integer> is a subtype of Map<?,?>. So it's OK to assign myMap.entrySet() to a variable of type Set<? extends Map<?,?>>.

Note that there's nothing special about String and Integer here, but myMap has to be a map of something!

You could write

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

这篇关于不兼容的通配符类型应该兼容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆