为什么你可以投射不同类型的地图?

时间:2011-08-07 17:09:35

标签: java casting map

我今天遇到一个奇怪的事情,我不太明白。拿这个代码,例如:

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>仍然没有错误?它应该只是一个字符串列表,但我可以从中检索一个整数。

我对此感到有点困惑,我想知道这里是否有人知道这些课程的内部运作能够帮助我。

2 个答案:

答案 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;
相关问题