PECS 泛型参数 逆变/协变/不变/无关
T 用于泛型类和泛型方法的定义
?用于泛型方法的调用和形参
T 只有extends一种限定方式,<T extends List>是合法的,<T super List>是不合法的
PECS
生产者(Producer)使用 extends,消费者(Consumer)使用 super。
逆变与协变用来描述类型转换(type transformation)后的继承关系,其定义:如果AA、BB表示类型,f(⋅)f(⋅)表示类型转换,≤≤表示继承关系(比如,A≤BA≤B表示AA是由BB派生出来的子类);
- f(⋅)f(⋅)是逆变(contravariant)的,当A≤B 时有f(B)≤f(A)成立;
- f(⋅)f(⋅)是协变(covariant)的,当A≤B 时有f(A)≤f(B)成立;
- f(⋅)f(⋅)是不变(invariant)的,当A≤B 时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。
数组是协变,泛型不是协变的,泛型具有无关性,不具备子父类关系
Number[] numbers = new Integer[3];
<? extends>
实现了泛型的协变
List<? extends Number> list = new ArrayList<Integer>();
<? super>
实现了泛型的逆变
List<? super Number> list = new ArrayList<Object>();
<? super Number>
表示list所持有的类型为在Number与Number的基类中的某一类型
,其中Integer与Float必定为这某一类型
的子类;所以add方法能被正确调用。
List<? super Number> list = new ArrayList<Object>();
list.add(new Integer(1));
list.add(new Float(1.2f));
生产者,写入/添加 ??
站在谁的角度??生产消费? 容器的角度,吃进去,吐出来
消费者,读取/获取 ??
如果你是想遍历collection,并对每一项元素操作时,此时这个集合是生产者(生产元素),应该使用 Collection<? extends Thing>.
如果你是想添加元素到collection中去,那么此时集合是消费者(消费元素)应该使用Collection<? super Thing>
最大接收。
<? extends Person> 上界--无穷小,小,岂止与小
get() 出来只确定最大是Person,最小不知道,故用Student接收错误(多态,子类 = 父类 不允许, 父类 = 子类 允许)
list1.add(Student ) 错误 ?可能比Student还想小 ? << Person
<? super Person> 下届-无穷大,大,岂止与大
list2.add(Student ) 正确 多态 ? >> Person 子类Student
list2.add(Person父类 ) 错误 ?可能在中间,不符合多态
PECS总结:指”Producer Extends, Consumer Super”
如果你想从一个数据类型里获取数据,使用 ? extends 通配符
如果你想把对象写入一个数据结构里,使用 ? super 通配符 super add 的笑容 消费者
如果你既想存,又想取,那就别用通配符。
泛型方法 E 与 泛型类 T 没关系
super add
泛型没有协变性,通配符使得容器有协变性!
拿出上界,添加下界,保证容器协变性
Java8 Stream
又如何解释??
Supplier<? extends T> s 生产者
void forEach(Consumer<? super T> action); 流容器消费
Stream<T> filter(Predicate<? super T> predicate); 容器消费数据
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Function<? super T 进去 消费者
? extends R> mapper 出来 生产者
深入泛型,以下链接很好,难懂
https://www.cnblogs.com/en-heng/p/5041124.html
https://blog.csdn.net/zy_jibai/article/details/90082239