Nested wildcards

后端 未结 2 1848
Happy的楠姐
Happy的楠姐 2020-12-04 02:15

Found fact about unbounded wildcards that is annoying me. For example:

public class Test {

      private static final Map

        
2条回答
  •  醉梦人生
    2020-12-04 02:34

    It is important to understand the implication of the wildcard types.

    You already understood that you can assign your Map> 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.

    In contrast, if you have a 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=new HashMap<>();
    map.put(null, Collections.singletonMap("foo", "bar"));
    map.put(null, Collections.singletonMap(42.0, 1000));
    map.put(null, Collections.singletonMap(false, true));
    

    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.

    So I’m quite sure that you don’t want to assign your Map> to a Map> and discover arbitrary maps not being Map 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> someMap = new HashMap<>();
    Map> map=someMap;
    

    In the generic type system Map 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 you can’t assign it to Map but only to Map 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> someMap = new HashMap<>();
    Map> map=Collections.unmodifiableMap(someMap);
    

    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.

提交回复
热议问题