繁体   English   中英

将 Y 添加到集合<x> , 而 Y 不是 instanceof X。为什么没有抛出运行时异常?</x>

[英]Add Y to Collection<X>, and Y not instanceof X. Why is no runtime exception thrown?

以下方法将任何内容添加到任何集合。 为什么没有抛出运行时异常?

public static <T> void addAnything(Collection<? super T> c, Object t) {
    c.add((T) t);
}

例如,

List<String> list = new ArrayList<>();
addAnything(list, "ok");
addAnything(list, 2);
addAnything(list, true);
addAnything(list, new Object())
addAnything(list, new Anything())

为什么这段代码没有抛出任何异常?

两个原因:向后兼容性和性能。

为了向后兼容旧的、不安全的代码,Java 中的 generics 是通过“类型擦除”实现的。 类型系统仅在编译时强制执行。 当您使用类型转换时,您是在告诉编译器“这很好,我知道我在做什么”,您只会得到一个警告。

在运行时添加对象时检查对象的类型会导致性能下降。 目前, ArrayList.add不需要知道关于添加的 object 的任何信息:它只适用于 object参考 这意味着 object 本身不需要从主 memory 加载到 CPU 寄存器或缓存中。 如果必须检查 object 的类型,缓存未命中的次数将急剧增加,从而减慢程序速度。

如果你想要一个确保只添加字符串的列表,你可以使用Collections.checkedList方法:

List<String> list = Collections.checkedList(new ArrayList<>(), String.class);
addAnything(list, 2); // run time error

因为所写的方法旨在将类型 Object 的实例添加到任何 T 超类型的列表中(而且您肯定知道,对于任何 T,Object 都是 T 的超类型)。 因此,该方法将您的List<String>视为List<Object>并向其添加 Object 的实例。 这显然是有效的行为。 如果您将非 String 对象添加到列表并尝试对其内容执行某些操作,您将看到异常。

由于类型擦除,运行时不会抛出异常。 基本上你的ArrayList<String>就像非泛型ArrayList一样被编译,这意味着你可以向它添加任何对象。

为什么添加过程中没有ClassCastException? ……为什么这段代码没有抛出任何异常?……

因为generics 在编译时被检查

您的代码就像这个经典示例中的代码 就像它在那里说的那样:“虽然代码编译没有错误,但它抛出运行时异常java.lang.ClassCastException ……”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM