Repeated projection of Java nested mapping

Why does the actor work?

import java.util.HashMap;
import java.util.Map;

public class TestMap {
    public static void main(String[] args) {
        Map<String,Map<String,Integer>>>> resultMap = new HashMap<>();
        Map<String,Object> aMap = new HashMap<String,Object>();
        Map<String,Integer> hiddenMap = new HashMap<String,Integer>();
        hiddenMap.put("fortytwo",42);
        aMap.put("key",hiddenMap);
        resultMap =  (Map<String,Integer>>>>) aMap.get("key");
        System.out.println(resultMap);
    }
}

This:

Map<String,Integer>>>>> resultMap = new HashMap<>();
...
resultMap =  (Map<String,Integer>>>>>) aMap.get("key");

Wait

How does this happen? Is the hidden map a map < string, integer > successfully converted to a map < string, map < string, integer > > > result map?

Always print:

{fortytwo = 42}

This also applies (not maps):

public static void main(String[] args) {

        Map<String,Integer>>>>> resultMap = new HashMap<>();
        Map<String,Map> aMap = new HashMap<String,Map>();
        Map<String,Integer>>>>>) aMap.get("key");
        System.out.println(resultMap);

    }

Editor: so @shizhz say, this is because of type erasure, of course! So the above code is equivalent to:

Map resultMap = new HashMap();
Map aMap = new HashMap();
Map hiddenMap = new HashMap();
hiddenMap.put("fortytwo",42);
aMap.put("key",hiddenMap);
resultMap = (Map) aMap.get("key");

This also works

Solution

Because Java generics are used at compile time to provide more stringent type checking, the compiler erases the type parameter according to the type error rules:

>If the type parameter is unbounded, replace all type parameters in the generic type with their boundaries or objects Therefore, the generated bytecode contains only ordinary classes, interfaces and methods. > Insert type castings if necessary to maintain type safety. > Generate bridging methods to preserve polymorphism in extended generic types

In the code map < string, Map > amap = new HashMap < string, Map > ();, The value in amap is the original type map, which means that when you try to convert the original type map to any generic type, the compiler does not know what type it contains. For maps such as map < string, integer >, the best compiler can do is give you a warning Generic types are erased at compile time, and type conversions are generated when you get values from generic mappings, so if the types do not match, you can only get runtime ClassCastException exceptions

Let's take a look at the following example:

public static void main(String[] args) {
    Map map = new HashMap();

    map.put("hello","world");
    map.put(new Integer(1),1);
    map.put(new Object(),Lists.newArrayList("hello"));

    Map<String,Integer> m =  (Map<String,Integer>) map;
    System.out.println(m);

    Integer i = m.get("hello");// ClassCastException happens at here at runtime
}

I am trying to convert a map containing various keys and values into a map < string, integer >, but there is no compilation error. After the type is erased, the above code is actually equivalent to:

public static void main(String[] args) {
    Map map = new HashMap();

    map.put("hello",Lists.newArrayList("hello"));

    Map m = (Map) map;
    System.out.println(m);

    Integer i = (Integer)m.get("hello");
}

Now you can easily tell why the last line causes ClassCastException

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>