文章目录
- 136. Java 泛型 - 下限通配符 (`? super T`)
- **1. 什么是下限通配符 (`? super T`)?**
- **2. 为什么使用下限通配符?**
- **3. 示例:使用 `? super Integer` 允许添加 `Integer`**
- **✅ 正确示例**
- **4. 为什么 `List<? super Integer>` 和 `List<Integer>` 不一样?**
- **❌ 错误示例**
- **5. 适用场景**
- **6. `? extends T` vs `? super T`**
- **7. 结论**
136. Java 泛型 - 下限通配符 (? super T)
在 Java 泛型中,下限通配符 (? super T) 允许指定某个类型的超类,使代码更具灵活性。
本篇将详细介绍下限通配符的概念,并结合示例帮助理解其应用。
1. 什么是下限通配符 (? super T)?
下限通配符 ? super T 表示T 类型或 T 的任意超类,即:
List<? super Integer>可以存储Integer及其所有父类(如Number、Object)。- 但由于类型不确定,读取元素时只能赋值给
Object。
✅ 下限通配符的语法
List<? super Integer> list;
list可以接受List<Integer>、List<Number>、List<Object>。- 可以安全地向
list添加Integer类型的元素。
2. 为什么使用下限通配符?
下限通配符 ? super T 适用于:
- 希望向集合中添加
T类型的元素(T及其父类)。 - 方法的逻辑仅依赖
T的超类,而不需要具体的T子类信息。 - 泛型方法中,确保集合能接收更广泛的类型范围。
3. 示例:使用 ? super Integer 允许添加 Integer
📌 需求:编写一个方法,向 List 中添加 Integer 值,支持 List<Integer>、List<Number> 和 List<Object>。
✅ 正确示例
import java.util.List;
import java.util.ArrayList;public class LowerBoundWildcard {public static void addNumbers(List<? super Integer> list) { // ✅ 适用于 Integer 及其超类for (int i = 1; i <= 10; i++) {list.add(i); // ✅ 安全添加 Integer}}public static void main(String[] args) {List<Integer> intList = new ArrayList<>();List<Number> numList = new ArrayList<>();List<Object> objList = new ArrayList<>();addNumbers(intList); // ✅ 可以传入 List<Integer>addNumbers(numList); // ✅ 可以传入 List<Number>addNumbers(objList); // ✅ 可以传入 List<Object>System.out.println(intList); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]System.out.println(numList); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]System.out.println(objList); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
}
🔍 解析
addNumbers(List<? super Integer>)可以接受List<Integer>、List<Number>、List<Object>。- 可以安全地向
list添加Integer,因为Integer一定是? super Integer允许的类型。 - 但无法保证从
list读取的数据类型(只能作为Object处理)。
4. 为什么 List<? super Integer> 和 List<Integer> 不一样?
在 Java 泛型中:
List<Integer>仅适用于Integer类型,无法存储Number或Object。List<? super Integer>可以存储Integer及其超类,如Number和Object,但无法确定列表存储的具体类型。
❌ 错误示例
List<? super Integer> list = new ArrayList<Number>();
Number num = list.get(0); // ❌ 编译错误
Integer i = list.get(0); // ❌ 编译错误
Object obj = list.get(0); // ✅ 只能赋值给 Object
🔍 为什么?
- Java 只保证
list里的元素是Integer的某个超类,但无法确定具体是什么类型。 - 只能读取为
Object,避免类型转换错误。
5. 适用场景
✅ 适用于“只写”数据的情况(向列表添加 T 类型数据)。
✅ 适用于泛型方法,提高灵活性(使方法接受 T 及其超类)。
✅ 适用于需要更广泛兼容性的集合(如 List<Number> 可以接收 Integer)。
6. ? extends T vs ? super T
| 通配符 | 适用情况 | 读取元素 | 添加元素 |
|---|---|---|---|
? extends T | 适用于只读场景(数据读取) | ✅ 可以读取为 T | ❌ 不能添加元素(除了 null) |
? super T | 适用于只写场景(数据存储) | ❌ 只能读取为 Object | ✅ 可以添加 T 类型的数据 |
7. 结论
✅ ? super T 表示某个类型 T 或 T 的超类。
✅ 适用于“写入数据”场景,确保方法能接收 T 及其超类的列表。
✅ 不能保证读取的数据类型,只能作为 Object 处理。
✅ 适用于泛型方法,使代码更加灵活和通用。
🎯 记住口诀:
? extends T适用于“读取”数据(如sum(List<? extends Number>))。? super T适用于“写入”数据(如addNumbers(List<? super Integer>))。- 使用
? super T,让 Java 泛型更灵活,兼容更多类型! 🚀