将地图投射到具有超类通用类型的地图

时间:2017-07-31 19:11:54

标签: java generics casting

我有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<String>转换为List<Object>时可能会出现什么问题,因为所有字符串都是对象?

我的具体问题:

我有一个Map<Integer, Map<Vector2i, MyClass> > map = ...,其中包含每个级别的地图。级别0上的地图是Map<Vector2i, MySubClass> special = ...类型。我现在希望special成为密钥0的map的一部分,以便可以将对密钥0的map的访问视为普通的Map<Vector2i, MyClass>对象。

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

1 个答案:

答案 0 :(得分:1)

  

投射List&lt; String&gt;时可能出错的地方到列表&lt;对象&gt;既然所有的字符串都是对象吗?

从这个角度来看:如果它是List<Object>,可以将所有内容添加到其中。所以,这可能会出错,例如:

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());
}

一旦ClassCastExceptions不符合预期,您就会点击String

<强> [附录]

  

为什么这(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<Number>并且只打印它们中的每一个。现在,您的代码中通常包含List<Integer>List<Double>等。但是以下代码将编译节点:

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

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

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

现在,该方法接受任何类型List的{​​{1}}个。但是您无法在方法内的列表中添加任何内容(在Number旁边),因为实际类型在运行时是未知的。

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