关键词:
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虽然很早就知道,也看过很多遍,但是记不牢,每次从单方面理解时,总是很绕,但是结合调用和使用两方面时,一切都合情合理,理解很简单。
源码
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(代码片段)
PECS是“ProducerExtendsConsumerSuper”的缩写,是Java泛型中的重要用法。PECS就是当你需要遍历某一个类型和子类的集合数据时,集合相当于生产者,此时泛型使用<?extendsT>。当需要往某个类型的集合添加类和子类实例时... 查看详情
java泛型pecs规则(producerextendsconsumersuper)(代码片段)
PECS关于泛型有个PECS(ProducerExtendsConsumerSuper)规则,说的是List<?extendsPerson>list=newArrayList();//编译错误,不允许往里添加元素,list.add(newPerson());//编译通过Personperson=lis 查看详情
java泛型中的pecs原则(代码片段)
...值,而不需要写值则使用"?extendsT“作为数据结构泛型。相反,当需要频繁写值,而不需要取值则使用”?superT" 查看详情
java泛型中的pecs原则(代码片段)
...值,而不需要写值则使用"?extendsT“作为数据结构泛型。相反,当需要频繁写值,而不需要取值则使用”?superT" 查看详情
java——泛型(代码片段)
文章目录Java中泛型的概述Java中泛型的语法规则泛型集合泛型方法泛型方法示例(代码演示)小结泛型类泛型类示例(代码演示)小结泛型接口泛型接口示例(代码演示)高级泛型总结Java中泛型的概述泛型... 查看详情
深入java泛型一泛型的作用与定义(代码片段)
第一章深入Java泛型一、泛型的作用与定义1.1泛型的作用1.2泛型的定义1.3泛型擦除一、泛型的作用与定义1.1泛型的作用使用泛型能写出更加灵活通用的代码。泛型的设计主要参照了C++的模板,旨在能让你写出更加通用化&... 查看详情
java泛型(代码片段)
文章目录前言一、泛型1.泛型的好处2.泛型的本质3.泛型类4.泛型接口5.泛型方法5.限定类型变量6.泛型的约束和局限性7.通配符类型总结前言提示:以下是本篇文章正文内容,下面案例可供参考一、泛型1.泛型的好处1.适用于... 查看详情
java重点--泛型(代码片段)
文章目录💖泛型的概念✨使用泛型的好处与弊端✨定义和使用含有泛型的类✨定义和使用含有泛型的方法✨定义和使用含有泛型的接口✨泛型的通配符✨通配符的高级使用--受限泛型✨斗地主小案例💖泛型的概念泛型是... 查看详情
深入java泛型(三泛型的上下边界)(代码片段)
第一章深入Java泛型三、泛型的上下边界3.1<?extendsE>:上界通配符(UpperBoundsWildcards)3.2<?superE>:下界通配符(LowerBoundsWildcards)3.3上下通配符的副作用三、泛型的上下边界?extendE是泛型的上边界... 查看详情
java泛型和内部类(代码片段)
文章目录一、泛型的概述1.概念2.泛型的定义3.泛型的使用4.泛型的意义5.泛型是如何编译的?二、泛型的进一步使用1.泛型类的定义-类型边界Number类2.泛型方法3.泛型中的父子类型4.通配符?通配符上界通配符下界5.泛型的... 查看详情
Java中数组和泛型的类型规则
】Java中数组和泛型的类型规则【英文标题】:TyperulesofarraysandgenericsinJava【发布时间】:2015-11-1117:53:31【问题描述】:EffectiveJava(2nd)第25条最后一段中说:数组和泛型有非常不同的类型规则。数组是协变的和reified;泛型是不变的... 查看详情
初识java集合及包装类和泛型的基本使用(代码片段)
....Collection接口说明2.Collection示例3.Map接口说明4.Map实例三、泛型1.泛型的分类2.泛型的定义3.泛型背后作用时期和背后的简单原理4.泛型的使用5.泛型总结四、包装类1.基本数据类型和包装类直接的对应关系2.包装类的使用,装箱(b 查看详情
集合类和java多线程(代码片段)
#知识点总结第五篇 1.泛型类就是带有参数类型的类,其类中也有属性和方法 数据类型可以实已有的类型,也可以是"类型参数"的类型。 2.泛型的好处 1.强制类型检查,在编译的时候就能得到类型错误的... 查看详情
Java泛型:包含泛型的数组[重复]
】Java泛型:包含泛型的数组[重复]【英文标题】:JavaGenerics:Arraycontaininggenerics[duplicate]【发布时间】:2011-12-2401:33:04【问题描述】:可能重复:Javahowto:GenericArraycreationErrorgenericarraycreation我的任务是用Java编写一个哈希表,它必须... 查看详情
java基础总结三(泛型异常)(代码片段)
文章目录Java基础总结三(泛型、异常)泛型泛型的创建泛型类泛型接口泛型方法类型擦除泛型的协变与逆变异常异常体系异常处理Java基础总结三(泛型、异常)泛型泛型的创建泛型类我们最常用泛型的地方就是... 查看详情
一个关于java泛型的疑问(代码片段)
之前对如下代码的区别不了解Stack<Integer>stack=newStack<Integer>();Stackstack1=newStack();现在写个demo理解下,主要区别为是否指定了泛型。importjava.util.ArrayList;importjava.util.Stack;/***@Description:TOD 查看详情
java遗珠之泛型的作用(代码片段)
泛型总共有三个作用编译时进行更强大的类型检查编译时错误比运行时错误更好发现和处理消除类型转换Listlist=newArrayList();list.add("hello");Strings=(String)list.get(0);使用泛型之后去掉转换List<String>list=newArrayList<Str... 查看详情
java笔记一问三不知------泛型的秘密(代码片段)
(还没有前言提要,后期补上:)泛型的创建和实例化1.常见创建使用(1)创建一个泛型类publicclassWrapper<T>privateTinstance;publicTgetInstance()returninstance;publicvoidsetInstance(Tinstance)this. 查看详情