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)
外,不能添加任何其他类型,为什么不能添加?
我们从调用方看看:
调用方中,方法的参数不能是 Object
和 Fruit
的集合,可以是 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()); } }
|