【问题标题】:Cast a Map to a map with super class generic types [duplicate]将地图转换为具有超类泛型类型的地图[重复]
【发布时间】:2017-07-31 19:11:54
【问题描述】:

我有一个Map<K, V> 并想将其转换为Map<K, U>,其中V 扩展了U。示例:我想从Map<String, String> 转到Map<String, Object>。各种集合都存在这个问题。

This question 已经有了一个“hacky”解决方案的答案,并且解释了为什么转换泛型类型通常是一个坏主意。但是让我们从 Voo 的回答中重新审视这个例子:

List<String> m = Something;
m.add("Looks good.");
m.add("42");
List<Object> s = (List<Object>)m; // (1) does not compile
List<Object> t = (List)m; // (2) compiles with warnings
Object myObject = s.get(1);

关于这个例子的几个问题:

  • 为什么这个 (1) 不能编译?除了 hack (2) 之外,还有其他方法可以让它编译吗?
  • 由于所有字符串都是对象,所以将 List&lt;String&gt; 转换为 List&lt;Object&gt; 时可能会出现什么问题?

我的具体问题:

我有一个Map&lt;Integer, Map&lt;Vector2i, MyClass&gt; &gt; map = ...,其中包含每个级别的地图。级别 0 上的地图类型为 Map&lt;Vector2i, MySubClass&gt; special = ...。我现在希望 special 成为键 0 的 map 的一部分,以便对键 0 的 map 的访问可以被视为普通的 Map&lt;Vector2i, MyClass&gt; 对象。

这种情况是只读的,这意味着写入mapspecial 是分开发生的。

【问题讨论】:

标签: java generics casting


【解决方案1】:

由于所有字符串都是对象,因此将 List 转换为 List 时可能会出现什么问题?

从这个角度来看:如果是List&lt;Object&gt;,则可以将所有内容添加到其中。因此,这可能会出错,例如:

List<Object> t = (List)m; // (2) compiles with warnings
t.add(1235); // it's a List<Object>, so we can add an Integer

for (String s : m) { // m only contains Strings, right?!
    System.out.println(s.length());
}

一旦s 不是预期的String,您就会遇到ClassCastException

[附录]

为什么这个 (1) 不能编译?除了hack(2)之外,还有一种方法可以让它编译吗?

我不确定,你的实际问题是什么,所以我只是猜测。但是我第一次遇到类似的问题,是这样的:

/* Just example; functionality does not matter, just that it accepts List<Number> */
public static void printNumbers(List<Number> numbers) {
    numbers.forEach(System.out::println);
}

上面的实用方法采用List&lt;Number&gt; 并仅打印它们中的每一个。现在您的代码中通常有List&lt;Integer&gt;List&lt;Double&gt; 等。但是下面的代码会编译节点:

List<Integer> integers = Arrays.asList(1, 2, 3);
printNumbers(integers);

现在,不要进行疯狂的强制转换(当然,如果您可以控制虚构的实用方法),请执行以下操作:

public static void printNumbers(List<? extends Number> numbers) {
    numbers.forEach(System.out::println);
}

现在该方法接受任何类型的Lists Numbers。但是你不能在方法内的列表中添加任何东西(除了null),因为实际的类型在运行时是未知的。

这个解释可能有点随意。如果您想了解更多细节,请搜索“PECS 规则”(“生产者扩展,消费者超级”)。当然,这同样适用于任何泛型类型,例如 Maps。

【讨论】:

  • 我明白了。我专注于“阅读”部分,完全忘记了在写作时仍然可能把事情搞砸。
  • 要添加的另一件事是“类型擦除”的概念,泛型是一种编译时间概念。演员可以在运行时通过List&lt;Object&gt; s = (List&lt;Object&gt;) List.class.cast(m); 完成,但它是一个潘多拉的盒子。如需更多见解,请参阅:stackoverflow.com/questions/14524751/…
  • '? extends´ 解决方案解决了我的问题,谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-08-26
  • 1970-01-01
  • 1970-01-01
  • 2017-09-22
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多