泛型通配符在什么情况下使用
大家好,我是程序员老王。今天咱们聊聊Java面试高频题:泛型通配符到底在什么情况下使用?这个问题看似基础,但能清晰回答的程序员还真不多。结合真实面试场景,我来给大家捋一捋思路。

📌 2025年Java面试宝典重磅更新!
链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g
提取码: 9b3g
(涵盖最新泛型面试题及深度解析)
一、 什么是泛型通配符?
简单说,泛型通配符就是那个神秘的?符号。它和T、K、V这类类型参数不同,泛型通配符代表“未知类型”。面试官最爱问:“List<String>和List<?>有啥区别?” 关键就在于泛型通配符让容器能接受任意类型,但牺牲了具体类型的安全性。
二、 必须用泛型通配符的3种场景
场景1:写通用工具方法(只读不写)
当你写的方法需要处理不同类型的集合,但不修改集合内容时,必须用泛型通配符。比如:
// 正确:用?通配符接收任意List
void printList(List<?> list) {
for (Object elem : list) System.out.println(elem);
}
// 错误:不用通配符会限制类型
void printList(List<Object> list) { ... } // 只能传List<Object>!
面试陷阱:如果这里用List<Object>,调用printList(Arrays.asList("A","B"))直接编译报错!这就是泛型通配符不可替代的原因。
场景2:实现灵活的API设计(PECS原则)
生产者(Producer)用<? extends T>,消费者(Consumer)用<? super T> 这是泛型通配符的核心用法。举个例子:
// 从src取数据(生产者),写入dest(消费者)
void copy(List<? extends Number> src, List<? super Number> dest) {
for (Number n : src) dest.add(n);
}
这里src可以是List<Integer>或List<Double>,而dest可以是List<Number>或List<Object>。没有泛型通配符,这种灵活性根本做不到。
场景3:规避泛型类型擦除的坑
由于Java泛型是类型擦除的,类似instanceof List<String>这种操作是非法的。此时泛型通配符是唯一解决方案:
if (list instanceof List<?>) { // 必须用通配符
// 安全地处理原始类型
}
三、 面试避坑指南
-
? vs T 的区别
T是类型变量,能声明变量(如T t = ...);?是实参,只能用于声明参数或变量。
错误回答:“它们可以互换” ❌
正确回答:“T用于定义泛型类/方法,?用于使用泛型” ✅ -
List<?>不能add()!
这是高频考点!因为编译器不知道?的具体类型,除null外任何add操作都会报错:List<?> list = new ArrayList<String>(); list.add("hello"); // 编译错误!

四、 通关技巧总结
| 场景 | 推荐写法 | 典型错误 |
|---------------------|--------------------------|------------------|
| 只读集合 | Collection<?> | Collection<T> |
| 接收子类集合 | List<? extends Number> | List<Number> |
| 接收父类集合 | List<? super Integer> | List<Object> |
最后提醒:如果大家需要购买面试鸭会员,可以通过面试鸭返利网找到我,返利25元!用省下的钱买杯咖啡刷题更香哦 ☕

(扫码直达优惠通道)
理解泛型通配符的关键在于抓住“灵活性”和“类型安全”的平衡点。下次面试被问到,不妨从PECS原则切入,绝对让面试官眼前一亮!


