通配符解决泛型不变性导致的类型兼容问题:无界?用于只读操作;? extends t用于生产者(读取t或其子类);? super t用于消费者(写入t或其父类);遵循pecs原则。

通配符在方法参数中主要解决泛型“不变性”带来的类型兼容问题。Java 中 List<string></string> 不是 List<object></object> 的子类型,哪怕 String 是 Object 的子类——这导致很多直觉上合理的调用会编译失败。通配符通过放宽类型约束,让方法能安全地接受更宽泛的泛型实参,从而提升 API 的通用性和复用性。
无界通配符 ?:只读场景下的通用入口
当你只需要遍历、检查或消费集合内容,不关心具体元素类型时,? 是最轻量的选择。
- 方法签名示例:
public void printAll(List> list) - 可传入
List<string></string>、List<integer></integer>、List<dog></dog>等任意类型列表 - 内部只能把元素当作
Object处理,不能调用add()(除null外),因为编译器无法确认实际类型 - 适合日志打印、统计大小、判空等与类型无关的操作
上界通配符 ? extends T:作为“生产者”时放宽输入
当方法从泛型结构中**读取**数据,并期望这些数据是某个类型的实例(或其子类)时,用 ? extends T。
- 典型场景:计算总和、查找最大值、批量转换
- 示例:
double sum(List extends Number> numbers)可接收List<integer></integer>、List<double></double>、List<bigdecimal></bigdecimal> - 可以安全地将每个元素当作
Number使用(如调用doubleValue()) - 但不能向该列表中添加任何元素(包括
Number或其子类),因为实际类型可能是List<integer></integer>,加Double会破坏类型安全
下界通配符 ? super T:作为“消费者”时拓宽写入目标
当方法需要向泛型结构中**写入**数据,且只要求目标容器能容纳某类型或其父类时,用 ? super T。
- 典型场景:批量添加、归并、收集结果
- 示例:
void addIntegers(List super Integer> dst)可接收List<integer></integer>、List<number></number>、List<object></object> - 可以安全地
add(new Integer(42)),因为所有这些目标类型都声明能存下Integer - 但从该列表中读出的元素只能当作
Object使用(因上界未知),无法直接调用intValue()
遵循 PECS 原则,避免误用
Producer-Extends, Consumer-Super —— 这是判断用哪个通配符的核心口诀。
- 参数用于“往外拿数据”(生产者)→ 用
? extends T - 参数用于“往里塞数据”(消费者)→ 用
? super T - 如果既要读又要写,就别用通配符,保持精确类型(如
List<t></t>) - 返回值类型一般不用通配符(如避免
List extends String>),否则调用方难以处理,应返回明确泛型如List<string></string>
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










