java泛型通配符核心是解决泛型不变性问题:?表示任意类型(只读object,不可add);

Java泛型通配符是面试高频考点,核心不是死记符号,而是理解“为什么需要它”和“在哪种场景下用哪个”。下面从三个最常被问到的角度直接给出清晰、可落地的回答逻辑。
通配符 ?、? extends T、? super T 的含义与限制
这三类通配符解决的是泛型类型之间“不协变”的问题——比如 List
- ?(无界通配符):代表任意引用类型,只能读取为 Object,不能添加任何元素(null 除外);适合只做遍历、不修改集合的场景。
-
? extends T(上界通配符):表示“T 或其任意子类”,例如
List extends Number>可接收List<integer></integer>、List<double></double>;能安全读取元素(返回值是 T 类型),但不能 add(除了 null),因为编译器不知道具体是哪个子类。 -
? super T(下界通配符):表示“T 或其任意父类”,例如
List super Integer>可接收List<number></number>、List<object></object>;能安全写入 T 类型对象(如 add(Integer)),但读取时只能当作 Object(无法保证具体类型)。
PECS 原则:一句话记住什么时候用哪个
这是面试加分项,也是设计泛型 API 的底层逻辑:
-
Producer Extends:如果你的集合是用来“往外提供数据”的(比如作为方法参数传入,只读不写),就用
? extends T。例如double sum(List extends Number> numbers)。 -
Consumer Super:如果你的集合是用来“往里存数据”的(比如接收新元素),就用
? super T。例如<t> void copy(List super T> dest, List extends T> src)</t>。
这个口诀直指本质:不是语法规则,而是角色决定通配符选择。
常见错误写法及面试追问点
面试官常通过反例考察你是否真懂:
-
错误:
List> list = new ArrayList<string>(); list.add("abc");</string>→ 编译失败。因为 ? 不知道具体类型,add 被禁止。 -
错误:
List extends Number> nums = new ArrayList<integer>(); nums.add(3.14);</integer>→ 编译失败。即使 3.14 是 Number 子类,编译器仍无法确认 nums 实际承载的是 Integer 还是 Double。 - 追问可能包括:“为什么不能同时支持读和写?”——答案是:泛型设计优先保障类型安全,放宽读写限制会破坏擦除后的运行时一致性。
掌握这三点,就能把通配符讲清楚、讲准确,不靠背诵,靠逻辑闭环。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











