Why does this cast work?
import java.util.HashMap;
import java.util.Map;
public class TestMap {
public static void main(String[] args) {
Map<String, Map<String, 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, Map<String, Map<String, Map<String, Integer>>>>) aMap.get("key");
System.out.println(resultMap);
}
}
also this:
Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
...
resultMap = (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");
and so on...
How does this happen that the hidden map which is Map<String, Integer> gets successfully cast to Map<String, Map<String, Map<String, Map<String,Integer>>>> resultMap?
Always prints:
{fortytwo=42}
Also this works (Map instead of Map):
public static void main(String[] args) {
Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
Map<String, Map> aMap = new HashMap<String, Map>();
Map<String, Integer> hiddenMap = new HashMap<String, Integer>();
hiddenMap.put("fortytwo", 42);
aMap.put("key", hiddenMap);
resultMap = (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");
System.out.println(resultMap);
}
EDIT: So as @shizhz says, it is because of Type Erasure of course! So the code above 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");
Which also works
Because java generics is used at compile time to provide tighter type checks, the type parameter is erased by compiler according Type Erasure rules:
In code Map<String, Map> aMap = new HashMap<String, Map>();, the value in aMap is a raw type Map, which means the compiler has no idea what's the type it contains, when you try to cast a raw type of Map to any generics type of Map like Map<String, Integer>, the best compiler can do is giving you a warning. The generic type is erased at compile time and type cast will be generated when you get value from a generic map, so you can only get a runtime ClassCastException exception if the type mismatchs.
Let's have 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'm trying to convert a Map containing all kinds of keys and values to Map<String, Integer> but there's no compile error, after type erasure, the above code is actually equivalent to:
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 m = (Map) map;
System.out.println(m);
Integer i = (Integer)m.get("hello");
}
Now you can easily tell why the last line caused ClassCastException.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With