Java 泛型的读写规则:PECS

PECS 是 “Producer Extends Consumer Super” 的缩写,是 Java 泛型中的重要用法。

PECS 就是当你需要遍历某一个类型和子类的集合数据时,集合相当于生产者,此时泛型使用 <? extends T>。当需要往某个类型的集合添加类和子类实例时,集合相当于消费者,此时泛型使用 <? super T>

每年八九月份的瓜是最甜的。

PECS

对 Java 泛型 PECS 的讲解中,大多是从参数使用的角度来的,本文结合调用传值和参数使用对比来看 PECS 的两种情况。

PE

当我们想要遍历读取某个集合时,需要使用 <? extends T>,用上面类型为例,为了方便查看编译时的错误,直接上截图:

当使用<? extends Watermelon>,类型的上限是 Watermelon,从集合取出的值默认就是 Watermelon,因此也能用父类定义去引用,所以方法前三个赋值正确,KylinWatermelon 错误。此时的集合除了可以 add(null) 外,不能添加任何其他类型,为什么不能添加?

我们从调用方看看:

调用方中,方法的参数不能是 ObjectFruit 的集合,可以是 Watermelons 和子类 KylinWatermelon,当这俩作为参数传递进去时,不能往 List<Watermelon> 中添加 Object, Fruit,不能往 List<KylinWatermelon>中添加 Object, Fruit,Watermelon。由于参数的类型不确定,因此除了null,其他都不能 add

CS

当需要往某个类型的集合添加类和子类实例时,集合相当于消费者,此时泛型使用 <? super T>

当使用<? super Watermelon>,类型的下限是 Watermelon。为了方便理解编译错误的原因,先看如何调用的方法:

调用时,参数必须是 Watermelon 或者父类型,当传递 objects, fruits, watermelons 时,从集合获取的类型是未知的,因此只能使用 Object 接收。当往集合添加值时,如果是 List<Watermelon> 就不能添加 Object, Fruit 类型,是 List<Fruit> 就不能添加 Object 类型,因此满足所有情况下的类型就只能是 Watermelon 和子类。

PECS虽然很早就知道,也看过很多遍,但是记不牢,每次从单方面理解时,总是很绕,但是结合调用和使用两方面时,一切都合情合理,理解很简单。

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class PECSLearn {
public static class Fruit {}

public static class Watermelon extends Fruit {}

public static class KylinWatermelon extends Watermelon {}

public static void main(String[] args) {
List<Object> objects = Arrays.asList(new Object());
List<Fruit> fruits = Arrays.asList(new Fruit());
List<Watermelon> watermelons = Arrays.asList(new Watermelon());
List<KylinWatermelon> kylinWatermelons = Arrays.asList(new KylinWatermelon());

producer(objects);//编译错误
producer(fruits);//编译错误
producer(watermelons);
producer(kylinWatermelons);

consumer(objects);
consumer(fruits);
consumer(watermelons);
consumer(kylinWatermelons);//编译错误
}

public static void producer(List<? extends Watermelon> watermelons) {
Object object = watermelons.get(0);
Fruit fruit = watermelons.get(0);
Watermelon watermelon = watermelons.get(0);
KylinWatermelon kylinWatermelon = watermelons.get(0);//编译错误

watermelons.add(null);
watermelons.add(new Object());//编译错误
watermelons.add(new Fruit());//编译错误
watermelons.add(new Watermelon());//编译错误
watermelons.add(new KylinWatermelon());//编译错误
}

public static void consumer(List<? super Watermelon> watermelons) {
Object object = watermelons.get(0);
Fruit fruit = watermelons.get(0);//编译错误
Watermelon watermelon = watermelons.get(0);//编译错误
KylinWatermelon kylinWatermelon = watermelons.get(0);//编译错误

watermelons.add(new Object());//编译错误
watermelons.add(new Fruit());//编译错误
watermelons.add(new Watermelon());
watermelons.add(new KylinWatermelon());
}
}

Java 泛型的读写规则:PECS
https://blog.mybatis.io/post/4fbc240a.html
作者
Liuzh
发布于
2022年9月26日
许可协议