不兼容的通配符类型应该兼容 [英] Incompatible wildcard types that should be compatible
问题描述
继续从这个问题,它提供了一个解决方案,但没有解释它(不幸的是,答案中的链接现在已经失效):
采取以下方法:
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 <?,?>>>
不是超类型 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屋!