在 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
具体的类型(Integer
?Double
?):
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
,甚至可能是Number
或Object
。 - 读取(读):只能将
list
中的元素读取为Object
,因为你无法确认具体的类型(它可能是Integer
、Number
,甚至是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);
}
}