Java泛型通配符核心是解决泛型不变性问题:?表示任意类型(只读Object,不可add);<? extends T>用于只读场景,可安全取T或其子类,禁止add;<? super T>用于只写场景,可安全add T及其子类,但读取仅得Object;遵循PECS原则——Producer Extends、Consumer Super。

Java泛型通配符是面试高频考点,核心不是死记符号,而是理解“为什么需要它”和“在哪种场景下用哪个”。下面从三个最常被问到的角度直接给出清晰、可落地的回答逻辑。
通配符 ?、? extends T、? super T 的含义与限制
这三类通配符解决的是泛型类型之间“不协变”的问题——比如 List<Integer> 并不是 List<Number> 的子类,哪怕 Integer 是 Number 的子类。编译器拒绝这种隐式转换,防止类型混乱。通配符就是为此引入的“安全桥梁”:
- ?(无界通配符):代表任意引用类型,只能读取为 Object,不能添加任何元素(null 除外);适合只做遍历、不修改集合的场景。
-
? extends T(上界通配符):表示“T 或其任意子类”,例如
List<? extends Number>可接收List<Integer>、List<Double>;能安全读取元素(返回值是 T 类型),但不能 add(除了 null),因为编译器不知道具体是哪个子类。 -
? super T(下界通配符):表示“T 或其任意父类”,例如
List<? super Integer>可接收List<Number>、List<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)。
这个口诀直指本质:不是语法规则,而是角色决定通配符选择。
立即学习“Java免费学习笔记(深入)”;
常见错误写法及面试追问点
面试官常通过反例考察你是否真懂:
-
错误:
List<?> list = new ArrayList<String>(); list.add("abc");→ 编译失败。因为 ? 不知道具体类型,add 被禁止。 -
错误:
List<? extends Number> nums = new ArrayList<Integer>(); nums.add(3.14);→ 编译失败。即使 3.14 是 Number 子类,编译器仍无法确认 nums 实际承载的是 Integer 还是 Double。 - 追问可能包括:“为什么不能同时支持读和写?”——答案是:泛型设计优先保障类型安全,放宽读写限制会破坏擦除后的运行时一致性。
掌握这三点,就能把通配符讲清楚、讲准确,不靠背诵,靠逻辑闭环。


















