嵌套通配符 [英] Nested wildcards

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

问题描述

发现有关使我烦恼的无限制通配符的事实.例如:

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<?, ?>.此子类型关系与StringObject的关系没有不同.您可以将任何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 Strings 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屋!

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