为什么可以插入 String
进入List<Integer>
在下面的代码中?我有一个将数字插入整数列表的类:
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(2);
list.add(3);
list.add(4);
Inserter inserter = new Inserter();
inserter.insertValue(list);
System.out.print(list);
}
}
然后我有一个单独的类,它插入一个 String
进入List
, 带有数字字符串值 "42"
:
public class Inserter {
void insertValue(List list)
{
list.add(new String("42"));
}
}
为什么编译器不引发编译器错误,或者运行时抛出运行时异常,例如*CastException
,当我添加 String
到整数列表?另外,为什么 System.out.print(list)
产生如下输出而不抛出任何异常?
[2, 3, 4, 42]
让这一切发生的根本原因是什么?
最佳答案
这可能是一个示例,用于说明泛型的 type erasure(我建议阅读该链接以完全理解这一点以及它在 Java 泛型中扮演的关键角色)。
-
list
声明为List<Integer>
- 当它作为参数传递给
listValue
时,它被转换为 raw type - 从此时开始,在该方法中,程序在运行时不知道它最初是一个“整数列表”,因此它可以无一异常(exception)地插入任何对象——在类声明中,类型变量被删除为
Object
† - 在 main 方法中,
print
命令只是调用列表中的toString
,它不关心它包含的内容,因此它会打印包括字符串在内的元素。
如果你想看到异常,尝试添加一行:
Integer myInt = list.get(3); // try to get the string
这将抛出 ClassCastException
,因为编译器会在删除期间在必要时插入强制转换以保护类型安全。
† 参数化类型(例如 List<Integer>
)转换为原始类型(例如 List
)会给您一个编译器警告,告诉您这种问题可能即将发生。您可以使用 @SuppressWarnings("unchecked")
(或 "rawtypes"
,如果它是 available to you )来抑制该警告。这是一种“确认”您将要执行的操作会导致未经检查的运行时异常的好方法,并且还有助于告诉其他 future 的编码人员可能会发生一些奇怪的事情。例如:
void insertValue(@SuppressWarnings("unchecked") List list)
{
list.add(new String("42"));
}
关于java - 为什么传递给 List 参数的 List<Integer> 上的 add(String) 不抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28236967/