为什么此嵌套的泛型转换会导致编译器错误

时间:2019-12-03 13:45:14

标签: java generics compiler-errors

不好意思,如果我以前曾问过这个问题(我几乎可以肯定),但是我找不到正确的关键词从一堆无关的泛型问题中找出答案。

简而言之

这有效:

vector-of

那为什么会出现编译器错误?

Object      a = null;
Set<Object> b = (Set<Object>)a;

为什么这个简单的解决方法有效?

Set<Object>      c = null;
Set<Set<Object>> d = (Set<Set<Object>>)c;

长版:(保留旧版,但不再与问题相关)

我有一个库方法,该方法返回经过预处理的JSON消息的Set<Object> e = null; Set<?> f = (Set<?>)e; Set<Set<Object>> g = (Set<Set<Object>>)f; 。进行手动深度类型检查后,我需要进行强制转换并将其返回为Map<Number, Object>,期望出现未经检查的强制转换警告,由于我刚刚对其进行了检查,因此我可以忽略该警告。

但是我遇到了编译器错误:

  

Map<Number, Map<String, Map<String, Object>>>

或以更具可读性的形式(基于IDE中的错误):

  

Error:(61, 10) java: Cannot cast from java.util.Map<java.lang.Number,java.lang.Object> to java.util.Map<java.lang.Number,java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.Object>>>

[edit] 操作方法问题更改为为什么问题。

2 个答案:

答案 0 :(得分:1)

请注意,由于泛型类型是在运行时删除的,因此在进行这些强制类型转换时实际上并没有发生实质性的变化。的确归结为“编译器允许这样做吗?”

泛型的目的之一是确保类型安全。如果由于某种原因可以将List<List<Object>>分配给List<Object>,则会丢失类型安全性:

List<List<Object>> listOfLists = new ArrayList<>();
List<Object> list = listOfLists; // suppose this is valid
list.add(new Object());
listOfLists.get(0); // what happens here?

(为方便起见,我在这里使用列表。您可以轻松地将其应用于地图或集合或任何其他通用类型)

listOfLists.get(0)将返回Object的实例,因为这是我们添加的内容,但是不会!因为它的类型是List<List<Object>>!这就是为什么像这样进行投射会破坏类型安全性的原因。

但是,以下两个强制转换是有效的:

List<Object>      e = null;
List<?>           f = (List<?>)e;
List<List<Object>> g = (List<List<Object>>)f;

List<?> f的意思是“ f是扩展Object的某个类的列表,但该类可以是任何东西”。请注意,List<?>List<Object>不同。您不能做f.add("String"),因为?不一定是String,对吗?

由于多数人(不正确地)认为可以将List<String>分配给List<Object>的相同原因而允许进行第一次强制转换。实际上,不需要此强制转换。 List<String> 是对List进行扩展的 Object

第二种转换是告诉编译器您知道?是什么,它就是List<Object>。编译器通过发出未经检查的警告来警告您?可能是错误的。

从某种意义上讲,您是在问为什么不能直接从Integer投射到String,但是可以先从Integer投射到Object,然后再投射到String

我觉得您的困惑可能是由于对<Object><?>之间的差异的误解引起的。 This post可能值得一读。

答案 1 :(得分:0)

这是因为泛型不支持子类型。以下代码也无法编译。

List<Number> numbers = new ArrayList<Integer>();

尽管NumberInteger的超类型,ArrayList<Number>不是ArrayList<Integer>的超类型。这些是完全不同的类型。

在您的情况下,您尝试将Object替换为Set<Object>