当前位置: 首页 > article >正文

理解Java泛型通配符:List<? extends T>与List<? super T>的深度解析

引言

在Java泛型系统中,通配符?是实现类型安全与灵活性的重要工具。其中List<? extends T>List<? super T>的差异常令开发者困惑。本文将通过理论解析、代码示例和实践场景,揭示它们的核心区别及应用场景。

一、基础概念

1.1 上界通配符(Upper Bounded Wildcard)

List<? extends T>声明了一个只读容器,表示集合元素是T或其子类:

void processNumbers(List<? extends Number> list) {
    Number n = list.get(0); // 安全读取
    // list.add(1); 编译错误!
}

此列表无法写入(除null),因实际类型可能是List<Integer>List<Double>

1.2 下界通配符(Lower Bounded Wildcard)

List<? super T>创建了可写容器,表示集合元素是T或其父类:

void fillIntegers(List<? super Integer> list) {
    list.add(42); // 安全写入
    Object obj = list.get(0); // 需强制转型
}

允许添加T类型元素,但读取时仅能获得Object类型。

二、核心差异对比

特性List<? extends T>List<? super T>
类型边界元素类型<=T元素类型>=T
数据流向生产者(数据输出)消费者(数据输入)
读取操作返回具体类型T返回Object
写入操作禁止(除null)允许添加T及其子类
典型应用场景计算结果/遍历元素收集数据/回调处理

三、PECS原则实践

3.1 Producer-Extends

当集合作为数据生产者时使用extends:

double sum(List<? extends Number> nums) {
    return nums.stream()
               .mapToDouble(Number::doubleValue)
               .sum();
}

可接受List<Integer>List<Double>等参数。

3.2 Consumer-Super

当集合作为数据消费者时使用super:

void pushAll(List<? super Integer> dest, List<Integer> src) {
    dest.addAll(src); // 安全注入数据
}

允许目标列表为List<Number>List<Object>

四、典型应用场景

4.1 集合工具类实现

观察java.util.Collections.copy()源码:

public static <T> void copy(
    List<? super T> dest, // 消费者
    List<? extends T> src // 生产者
) {
    for (int i=0; i<src.size(); i++)
        dest.set(i, src.get(i));
}

该设计确保:

  • 源集合安全输出元素

  • 目标集合安全接收元素

4.2 回调处理模式

interface Processor<T> {
    void process(List<? super T> results);
}

void execute(Processor<? super String> processor) {
    processor.process(new ArrayList<Object>());
}

允许处理器处理更宽泛的结果类型。

五、常见误区解析

5.1 错误写入extends列表

List<? extends Number> nums = new ArrayList<Double>();
nums.add(1.0); // 编译错误!

编译器无法确认实际类型是否匹配。

5.2 错误读取super列表

List<? super Integer> list = new ArrayList<Number>();
Integer i = list.get(0); // 需要显式转型
Object obj = list.get(0); // 安全方式

六、进阶应用技巧

6.1 多重边界组合

<T extends Comparable<? super T>> void sort(List<T> list) {
    // 支持父类实现Comparable的情况
}

允许T或其父类实现比较接口。

6.2 类型推断优化

static <T> void copy(
    List<? super T> dest,
    List<? extends T> src
) {
    // 更优的类型推断
}

相比非通配符版本,增强API灵活性。

结语

理解extendssuper通配符的本质差异,关键在于把握数据流动方向。遵循PECS原则可使代码兼具类型安全与灵活性。建议在以下场景选择:

  • 需要只读访问时使用? extends T

  • 需要写入操作时使用? super T

  • 同时需要读写时避免使用通配符

通过合理运用这些特性,开发者可以构建出更健壮、更灵活的泛型API,有效平衡类型约束与代码复用需求。


http://www.kler.cn/a/577919.html

相关文章:

  • Django模型数据修改:详解两种方式
  • 阿里巴巴全新推理模型QwQ-32B:性能比肩DeepSeek-R1,开源引领未来
  • 文本处理Bert面试内容整理-BERT的优点是什么?
  • 数据结构【AVL树(平衡二叉树)】
  • 一体式 IO 模块助力 PLC,开启纺织机自动化高效新篇章
  • MYOJ_4204:迷宫(图论-网格图基础,dfs,bfs在网格图中应用)
  • 【蓝桥杯集训·每日一题2025】 AcWing 5538. 回文游戏 python
  • React-路由配置
  • 读书会-c#并发编程
  • C++ 二叉搜索树代码
  • 支付宝当面付java,php,sdk下载
  • 14.DS18B20温度传感器
  • springboot + mybatis
  • Linux下搭建本地deepseek(附文档下载)
  • AI大模型学习(五): LangChain(四)
  • 《Go语言设计与实现》Runtime部分的一些知识总结
  • 【RabbitMQ】Producer之TTL过期时间 - 基于AMQP 0-9-1
  • SSM架构 +Nginx+FFmpeg实现rtsp流转hls流,在前端html上实现视频播放
  • 【蓝桥杯集训·每日一题2025】 AcWing 5540. 最大限度地提高生产力 python
  • Python读取json文件