通透解析 Java 泛型中的 <? extends T> 和 <? super T>(上界和下界通配符)

       在 Java 中,泛型的上界和下界是为了解决灵活性类型安全之间的冲突。通过上界 ? extends T下界 ? super T,我们可以控制泛型中元素的读写权限

1️⃣ <? extends T>:上界通配符

"只读,不写" —— 只能读取数据,不能往里面写入数据。

语法含义

? extends T 表示该泛型可以接受 T 本身或 T 的子类

常见用法
  • 生产者(Producer):数据的**输出(读取)**操作。
  • 典型场景:处理一个返回 T 或 T 子类的集合
示例 1:上界的简单用法
import java.util.List;

public class Main {
    public static void printList(List<? extends Number> list) {
        for (Number num : list) {
            System.out.println(num);
        }
    }

    public static void main(String[] args) {
        List<Integer> intList = List.of(1, 2, 3);
        List<Double> doubleList = List.of(1.1, 2.2, 3.3);

        printList(intList);     // OK,Integer 是 Number 的子类
        printList(doubleList);  // OK,Double 是 Number 的子类
    }
}
🔍 关键点
  • 读取(读)Number num 可以从 list 中获取到元素,因为 ? extends Number 确保列表中的每个元素都是 Number 或其子类。
  • 写入(写):不允许向 list 中添加元素,除了 null,因为你无法确定 list 具体的类型(IntegerDouble?):
list.add(1);     // ❌ 编译错误,无法确认 T 是什么
list.add(1.1);   // ❌ 编译错误
list.add(null);  // ✅ 允许,因为 null 适配任何引用类型
总结
  • <? extends T> 主要用于从集合中读取数据,但不允许向集合中写入数据(除了 null)。
  • 适用于生产者模式(生产数据给你用)。

 

2️⃣ <? super T>:下界通配符

"只写,不读" —— 只能往里面写入数据,读取出来的数据只能是 Object

语法含义

? super T 表示该泛型可以接受 T 本身或 T 的父类

常见用法
  • 消费者(Consumer):数据的**输入(写入)**操作。
  • 典型场景:向一个接受 T 或 T 父类的集合中添加数据
示例 2:下界的简单用法
import java.util.List;
import java.util.ArrayList;

public class Main {
    public static void addElements(List<? super Integer> list) {
        list.add(1); // ✅ 可以
        list.add(2); // ✅ 可以
        list.add(3); // ✅ 可以
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        List<Object> objectList = new ArrayList<>();
        
        addElements(numberList); // OK,因为 Number 是 Integer 的父类
        addElements(objectList); // OK,因为 Object 是 Integer 的父类

        // 不能传 List<Double>,因为 Double 不是 Integer 的父类
        // addElements(List<Double> doubleList); // ❌ 编译错误
    }
}
🔍 关键点
  • 写入(写):可以向 list 中添加 Integer,因为 ? super Integer 表示 list 至少是 Integer,甚至可能是 NumberObject
  • 读取(读):只能将 list 中的元素读取为 Object,因为你无法确认具体的类型(它可能是 IntegerNumber,甚至是 Object)。
Object obj = list.get(0);  // ✅ 只能读取成 Object,因为你不确定是什么类型
Integer num = list.get(0); // ❌ 编译错误,无法确保是 Integer

 

3️⃣ 对比总结:<? extends T> vs <? super T>

通配符类型边界读操作写操作常见场景
? extends T上界T 及其子类✅ 允许读取(返回 T 类型)❌ 不允许写入(除 null)只从集合中读取数据
? super T下界T 及其父类❌ 读取只能返回 Object✅ 允许写入 T 及其子类向集合中写入数据

4️⃣ 何时用 extends,何时用 super

  • 如果需要"从集合中读取数据"**,用 ? extends T

    生产者(Producer)原则:PECS (Producer Extends, Consumer Super)

  • 如果需要"向集合中写入数据"**,用 ? super T

    消费者(Consumer)原则:PECS (Producer Extends, Consumer Super)

记忆口诀
  • **extends - 读出**extends 出
  • **super - 写入**super in

5️⃣ 综合示例 

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void processElements(List<? extends Number> producer, List<? super Integer> consumer) {
        // 1️⃣ 读取 producer 中的元素
        for (Number num : producer) {
            System.out.println("Producer: " + num);
        }
        
        // 2️⃣ 写入数据到 consumer 中
        consumer.add(10); // ✅ 允许添加 Integer
        consumer.add(20); // ✅ 允许添加 Integer
        
        // 3️⃣ 读取 consumer 中的元素
        Object obj = consumer.get(0); // 只能读取成 Object
        System.out.println("Consumer: " + obj);
    }

    public static void main(String[] args) {
        List<Integer> producerList = List.of(1, 2, 3);
        List<Number> consumerList = new ArrayList<>();
        
        processElements(producerList, consumerList);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大怪~将军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值