Java泛型List<? extends Double>下add报错但remove可编译的原因
核心原因解析
这个现象本质是Java泛型通配符上界? extends T的协变约束规则,和List接口不同方法的签名设计共同导致的,具体分两部分说明:
- 为什么
add方法编译失败List<? extends Double>的含义是:该列表的实际元素类型是Double或它的某一个未知子类,编译器无法确认这个列表的实际类型到底是什么。而add方法的签名是boolean add(E e),入参要求和列表泛型类型完全匹配,只要编译器无法验证传入对象符合列表的实际未知类型,就会直接拦截所有add调用,哪怕你传入的是Double类型对象也不行,避免出现类型安全问题。
哪怕Double是final类不存在子类,Java泛型的校验规则也不会单独对final类做例外处理,add限制仍然生效。 - 为什么
remove方法可以正常编译
注意List的remove方法签名是boolean remove(Object o),它的入参根本不是泛型类型E,而是最顶层的Object。该方法的逻辑是只要传入对象和列表中元素equals比对一致就执行删除,不需要匹配泛型约束,哪怕你传入完全不相关的类型(比如String)调用remove也能编译通过,只是运行时会返回false而已,所以完全不会被? extends的通配符约束限制。
补充说明:很多资料里提到的? extends让列表进入「只读模式」是简化表述,实际它只是限制了写入操作中涉及泛型类型匹配的方法,不涉及泛型入参的修改方法(比如remove、clear)都可以正常调用。
内容的提问来源于stack exchange,提问作者Rafael_Kuai
相关产品推荐
相关产品推荐

