Java:将对象转换为通用类型

19

在Java中,从一个对象转换为其他类型时,为什么第二行会产生与转换相关的警告,而第一行不会?

void a(Object o) {
  Integer i = (Integer) o;
  List<Integer> list = (List<Integer>) o;
}

/*Type safety: Unchecked cast from Object to List<Integer>*/

第二行会产生一个警告,因为只有泛型才会生成这样的警告。第一行不包含泛型,因此没有警告。 - Hot Licks
3个回答

27

这是因为由于类型擦除,在执行时对象实际上不会被检查是否为List<Integer>。它实际上只是将其强制转换为List。例如:

List<String> strings = new ArrayList<String>();
strings.add("x");
Object o = strings;

// Warning, but will succeeed at execution time
List<Integer> integers = (List<Integer>) o;
Integer i = integers.get(0); // Bang!

请查看Angelika Langer的Java泛型FAQ以获取更多信息,特别是类型擦除部分


9
为了更清晰明白,让我稍微改写一下这些例子…
我认为,以下两者之间的关键区别是:
void a(Object o) {
  Integer i = (Integer) o;
  ...
}

and

void a(Object o) {
  List<Integer> list = (List<Integer>) o;
  ...
}

假设存在类型错误,第一次转换将在执行时立即抛出运行时异常(具体来说是ClassCastException)。

而只要输入参数o是任何类型的List<?>,第二个可能就不会——尽管有错误转换,执行也会继续进行

代码是否会在稍后抛出异常取决于您对列表的操作。

但不管怎样,在强制类型转换处不会抛出异常,而是可能在其他地方(这可能是一个难以跟踪的错误)或根本不抛出异常。

这就是我理解的,编译器设计者认为仅在第二种情况下使用警告的原因。


第一个代码不一定会抛出CastClassException异常。传入的对象很可能是一个Integer。第一行代码可能会抛出异常,就像第二个代码一样,如果o不是一个List的话也可能会抛出异常。 - Hot Licks
@Hot Licks:是的,这就是我为什么在上面写了“假设存在类型错误”的原因 - 我甚至加粗了它 ;) - Rop

9

Jon的答案是正确的,但有时你无法避免这个警告(比如在使用遗留API时)。在这种情况下,你可以这样禁止警告:

@SuppressWarnings("unchecked")
List<Integer> list = (List<Integer>) someApiThatReturnsNonGenericList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接