天天看点

Java 泛型的读写规则:PECS

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

PECS 就是当你需要遍历某一个类型和子类的集合数据时,集合相当于生产者,此时泛型使用 ​

​<? extends T>​

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

​<? super T>​

​。

Java 泛型的读写规则:PECS
每年八九月份的瓜是最甜的。

PECS

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

Java 泛型的读写规则:PECS

PE

当我们想要遍历读取某个集合时,需要使用 ​

​<? extends T>​

​,用上面类型为例,为了方便查看编译时的错误,直接上截图:

Java 泛型的读写规则:PECS

当使用​

​<? extends Watermelon>​

​​,类型的上限是 ​

​Watermelon​

​​,从集合取出的值默认就是 ​

​Watermelon​

​​,因此也能用父类定义去引用,所以方法前三个赋值正确,​

​KylinWatermelon​

​​ 错误。此时的集合除了可以 ​

​add(null)​

​ 外,不能添加任何其他类型,为什么不能添加?我们从调用方看看:

Java 泛型的读写规则:PECS

调用方中,方法的参数不能是 ​

​Object​

​​ 和 ​

​Fruit​

​​ 的集合,可以是 ​

​Watermelons​

​​ 和子类 ​

​KylinWatermelon​

​​,当这俩作为参数传递进去时,不能往 ​

​List<Watermelon>​

​​ 中添加 ​

​Object, Fruit​

​​,不能往 ​

​List<KylinWatermelon>​

​​中添加 ​

​Object, Fruit,Watermelon​

​​。由于参数的类型不确定,因此除了​

​null​

​​,其他都不能 ​

​add​

​。

CS

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

​<? super T>​

​。

Java 泛型的读写规则:PECS

当使用​

​<? super Watermelon>​

​​,类型的下限是 ​

​Watermelon​

​。为了方便理解编译错误的原因,先看如何调用的方法:

Java 泛型的读写规则:PECS

源码

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());
    }
}