Java泛型中<T extends Foo>和<? extends Foo>有什么区别?
Java泛型
<? extends Base>与<T extends Base>的区别及代码修正 二者核心区别
<? extends Base>是通配符上限声明,属于未知类型限定:它仅表示容器内存储的元素是Base或其子类的某一种固定类型,但编译器无法获知具体是哪一个类型。为了保证类型安全,编译器会禁止向这类容器中写入任何非null的元素,因为无法验证待写入元素的类型和容器实际存储的未知类型是否匹配。<T extends Base>是泛型类型参数声明,属于确定类型限定:这里的T是具体的类型占位符,在方法被调用时会根据传入的参数类型确定具体类型,同一方法调用周期内T的类型是固定的,仅要求满足「是Base的子类」这个限定条件。
报错原因
你将hashMap声明为HashMap<Integer, ? extends Base>,本质上已经限制了该容器只能执行读取操作,无法执行写入操作。即使put方法声明了<T extends Base>,编译器也无法验证T和容器实际存储的未知类型是否兼容,因此直接抛出类型不兼容错误。
正确改写方案
如果你的需求是允许该容器存储所有Base及其子类的实例,直接移除通配符声明即可,修正后代码如下:
abstract public class Base { private static final HashMap<Integer, Base> hashMap = new HashMap<>(); public static <T extends Base> void put(Integer key, T val) { hashMap.put(key, val); } @SuppressWarnings("unchecked") public static <T extends Base> T get(Integer key) { return (T) hashMap.get(key); } }
补充说明
- 将容器声明改为
HashMap<Integer, Base>后,所有Base及其子类的实例都可以正常写入,完全符合通用存储的需求。 get方法添加的@SuppressWarnings("unchecked")注解是为了屏蔽类型强转的警告,只要调用方put和get时使用的类型一致,就不会出现实际运行时的类型转换异常,这是Java中这类全局泛型容器的标准写法。
内容的提问来源于stack exchange,提问作者PlMem
相关产品推荐
相关产品推荐

