【问题标题】:Why can you cast Maps of different types?为什么可以投射不同类型的地图?
【发布时间】:2011-08-07 17:09:35
【问题描述】:

我今天遇到了一个我不太明白的怪事。以这段代码为例:

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

对此我有点困惑,我想知道这里是否有人对这些类的内部工作有足够的了解来帮助我。

【问题讨论】:

  • 代码的前四行无法编译。 iMap 至少需要声明为 Map。
  • @Hovercraft 不正确。自己试试这个代码。它编译。
  • @JakeKing:我在输入评论之前确实对此进行了测试。但没关系,因为这是一个基本的 Java 错误,而且它不应该编译。

标签: java casting map


【解决方案1】:

您可以将Map&lt;Integer, Object&gt; 转换为Map&lt;String, Object&gt;“没有任何问题”...直到您尝试使用它。

问题从这一行开始:

Map<String, Object> sMap = (Map<String, Object>)iMap;

编译器通过以下消息警告您的位置:

类型安全:从 Object 到 Map 的未经检查的强制转换

你忽略了那个警告。

这一切都是因为runtime type erasure 而发生的——在运行时没有类型,例如你只有Map 等。类型只是在编译时帮助你做你想做的事正在这里做。

这条线爆炸的原因:

String s = new ArrayList<String>(sMap.keySet()).get(0);

sMap 实际上是指在其条目中具有整数作为键的 Map。当您实际拔出其中一个键时,它是一个 Integer,然后 java 尝试将其分配给一个 String...繁荣!

顺便说一句,这部分没有编译:

Object iMap = new HashMap<Integer, Object>();
iMap.put(5, "thing1");
iMap.put(6, "thing2");

您需要像这样将 iMap 转换为 Map&lt;Integer, Object&gt;

Object iMap = new HashMap<Integer, Object>();
((Map<Integer, Object>)iMap).put(5, "thing1");
((Map<Integer, Object>)iMap).put(6, "thing2");

【讨论】:

  • 啊,当然!在使用泛型时,我似乎总是忘记这一点。我会尽快接受。 (StackOverflow 很棒。)
  • 是的,我修复了“未编译”部分。当我对此进行一个小测试时,我使用了惰性的“双括号初始化”方法。
【解决方案2】:

您的代码的前四行将无法编译,因为 iMap 必须至少声明为 Map 才能在其上调用 get(...) 等方法。但是您的另一个问题说明了为什么在声明变量时使用泛型很重要。因此,如果您这样声明 iMap:

  Map<Integer, Object> iMap = new HashMap<Integer, Object>();

当您尝试在此处强制转换时,编译器会正确地抱怨:

Map<String, Object> sMap = (Map<String, Object>)iMap;

【讨论】:

  • 不,不会。正如我对这个问题的评论,我已经对此进行了测试。它编译并运行。
  • 不适用于我熟悉的任何 Java 编译器。
  • 我收回了。我的代码略有不同,我将更新我的第一篇文章。对不起。
猜你喜欢
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-04
  • 2011-09-20
  • 1970-01-01
  • 2015-05-24
相关资源
最近更新 更多