我今天遇到一个奇怪的事情,我不太明白。拿这个代码,例如:
Object iMap = new HashMap<Integer, Object>() {{
put(5, "thing1");
put(6, "thing2");
}};
Map<String, Object> sMap = (Map<String, Object>)iMap;
// No error, prints out java.lang.Integer:
System.out.println(new ArrayList(sMap.keySet()).get(0).getClass().getName();
// No error, prints out 5:
Object key = new ArrayList<String>(sMap.keySet()).get(0);
System.out.println(key.toString());
// ClassCastException:
String s = new ArrayList<String>(sMap.keySet()).get(0);
那么,是什么给出的?为什么我可以将具有Integer类型的键的Map转换为String类型而没有任何问题?不应该抛出错误吗?为什么我甚至可以转换为ArrayList<String>
而仍然没有错误?它应该只是一个字符串列表,但我可以从中检索一个整数。
我对此感到有点困惑,我想知道这里是否有人知道这些课程的内部运作能够帮助我。
答案 0 :(得分:3)
您可以Map<Integer, Object>
“Map<String, Object>
”将Map<String, Object> sMap = (Map<String, Object>)iMap;
“强制转换为”......直到您尝试使用它为止。
问题从这一行开始:
Map
编译器使用此消息警告您:
类型安全:从对象到地图的未选中投射
你忽略了那个警告。
这都是因为runtime type erasure而发生的 - 在运行时没有类型,例如你只有String s = new ArrayList<String>(sMap.keySet()).get(0);
等等。类型就在编译时就是为了帮助你而不是做你在这做的事。
这条线爆炸的原因:
Object iMap = new HashMap<Integer, Object>();
iMap.put(5, "thing1");
iMap.put(6, "thing2");
是sMap实际上是指其条目中具有整数键的Map。当你真正去掉其中一个键时,它是一个整数,然后java尝试分配给一个String ... boom!
顺便说一句,这部分不编译:
Map<Integer, Object>
您需要将iMap投射到Object iMap = new HashMap<Integer, Object>();
((Map<Integer, Object>)iMap).put(5, "thing1");
((Map<Integer, Object>)iMap).put(6, "thing2");
,如下所示:
{{1}}
答案 1 :(得分:0)
代码的前四行不会编译,因为iMap必须至少声明为Map才能调用get(...)等方法。但是你的另一个问题说明了为什么在声明变量时使用泛型很重要。所以如果你这样声明了iMap:
Map<Integer, Object> iMap = new HashMap<Integer, Object>();
当您尝试在此处投射时,编译器会正确地抱怨:
Map<String, Object> sMap = (Map<String, Object>)iMap;