嵌套通配符 [英] Nested wildcards
问题描述
发现有关使我烦恼的无限制通配符的事实.例如:
Found fact about unbounded wildcards that is annoying me. For example:
public class Test {
private static final Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
public static void main(String[] args) {
getSomeMap();
}
static Map<?, Map<?, ?>> getSomeMap() {
return someMap; //compilation fails
}
}
它失败,尽管可以与Map<?, ?>
或Map<?, Map<Integer, String>>
返回类型一起使用.
It fails, although works with Map<?, ?>
or Map<?, Map<Integer, String>>
return type.
有人可以告诉我确切的原因吗?预先感谢.
Could someone tell me the exact reason? Thanks in advance.
更新
我认为,对于该问题,我理解的最简单的解释(忽略所有这些复杂的规则)是Capture Conversion(
Seems that i understood and the simplest explanation for this question(omitting all these sophisticated rules), in my opinion, is the last note in Capture Conversion(link): Capture conversion is not applied recursively.
推荐答案
理解通配符类型的含义很重要.
It is important to understand the implication of the wildcard types.
您已经了解可以将Map<Integer, Map<Integer, String>>
分配给Map<?, ?>
,因为Map<?, ?>
表示任意类型,对于引用了声明的类型Map<?, ?>
的人来说是未知的.因此,您可以将 any 映射分配给Map<?, ?>
.
You already understood that you can assign your Map<Integer, Map<Integer, String>>
to Map<?, ?>
as Map<?, ?>
implies arbitrary types, unknown to whoever might have a reference of the declared type Map<?, ?>
. So you can assign any map to Map<?, ?>
.
相反,如果您有Map<?, Map<?, ?>>
,则其键类型未知,但值类型为 not 未知.是Map<?,?>
类型,可以回忆上面的信息,可以通过 any 映射进行分配.
In contrast, if you have a Map<?, Map<?, ?>>
it has an unknown key type but the value type is not unknown. It’s Map<?,?>
the type, recall the information above, that can be assigned with any map.
因此,以下代码是合法的:
So, the following code is legal:
Map<?, Map<?, ?>> map=new HashMap<>();
map.put(null, Collections.<String,String>singletonMap("foo", "bar"));
map.put(null, Collections.<Double,Integer>singletonMap(42.0, 1000));
map.put(null, Collections.<Object,Boolean>singletonMap(false, true));
在这里,我们将放置null
键,因为对于键,我们将无法再执行put
其他任何操作,但是将任意类型的映射作为值,这就是Map<?, ?>
的值类型所隐含的含义:可以从任意映射中进行分配.请注意,通过迭代条目我们还可以设置其他具有非null
键的任意条目.
Here, we are putting a null
key as we can’t put
anything else for keys but arbitrary typed maps as values as that’s what a value type of Map<?, ?>
implies: can be assigned from arbitrary maps. Note that by iterating over the entries we can also set other entries having non-null
keys to arbitrary maps then.
因此,我非常确定您不想将Map<Integer, Map<Integer, String>>
分配给Map<?, Map<?, ?>>
并随后发现不属于Map<Integer, String>
的任意映射作为值,并且您很高兴编译器没有允许这个.
So I’m quite sure that you don’t want to assign your Map<Integer, Map<Integer, String>>
to a Map<?, Map<?, ?>>
and discover arbitrary maps not being Map<Integer, String>
as values afterwards and that you are quite happy that the compiler doesn’t allow this.
您实际要做的是将地图分配给同时具有键和值类型的类型,该类型未知,但仍然告诉您值是地图:
What you actually want to do is to assign your map to a type which has both, key and value type, unknown but still telling that your values are maps:
Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, ? extends Map<?, ?>> map=someMap;
在通用类型系统中,Map<Integer, String>
是Map<?, ?>
的子类型,因此您可以将其分配给Map<?, ?>
和? extends Map<?, ?>
.此子类型关系与String
到Object
的关系没有不同.您可以将任何String
分配给Object
类型的变量,但是由于相同的原因,如果您拥有Map<?,String>
,则不能将其分配给Map<?,Object>
,而只能分配给Map<?, ? extends Object>
: String
s作为值而不是接收任意对象.
In the generic type system Map<Integer, String>
is a sub-type of Map<?, ?>
so you can assign it to Map<?, ?>
as well as ? extends Map<?, ?>
. This sub-type relationship is not different than the relationship of String
to Object
. You can assign any String
to a variable of type Object
but if you have a Map<?,String>
you can’t assign it to Map<?,Object>
but only to Map<?, ? extends Object>
for the same reason: the map shall continue to contain String
s as values rather than receiving arbitrary objects.
请注意,您可以解决此限制.你可以说:
Note that you can workaround this limitation. You can say:
Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, Map<?, ?>> map=Collections.unmodifiableMap(someMap);
由于unmodifiableMap
返回的映射不允许进行任何修改,因此它允许扩展键和值类型.查询映射时,所包含的值具有指定的类型(即Map<?, ?>
),但是尝试放入任意映射值(尽管编译器未拒绝)但将在运行时被拒绝.
Since the map returned by unmodifiableMap
does not allow any modifications, it allows widening the key and value types. The contained values are of the specified type (i.e. Map<?, ?>
) when you query the map, but attempts to put in arbitrary map values, while not rejected by the compiler, will be rejected at runtime.
这篇关于嵌套通配符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!