<? extends T>
和<? super T>
的使用
- <? extends T> : 上界通配符(Upper Bounds Wildcards)
- <? super T> : 下界通配符(Lower Bounds Wildcards)
先定义三个类
public class Tea {}
public class GreenTea extends Tea {}
public class BlackTea extends Tea {}
再定义一个容器类
@Data
@AllArgsConstructor
public class Cup<T> {
private T t;
}
定义一个茶杯让它去装绿茶
Cup<Tea> teaCup = new Cup<GreenTea>(new GreenTea());
这个操作 Java 会报错
Incompatible types.
Required: Cap<Tea>
Found: Cap<GreenTea>
那么问题来了,按照我们的逻辑,茶杯去装绿茶是完全可以的,但编译器认为茶杯只能装“茶”,
编译器的世界里:
- 绿茶 IS-A 茶
- 装绿茶的杯子 NOT-IS-A 装茶的杯子
所以上下界通配符的出现就能让“装绿茶的杯子”和“装茶的杯子”关联起来
那么现在定义一个上界
Cup<? extends Tea> teaCup
这个 teaCup 能盛茶和所有茶的子类,说直白点就是能盛所有的茶,所以现在这个杯子里是可以装绿茶的
Cup<? extends Tea> teaCup = new Cup<>(new GreenTea());
那么同时出现了另一个问题,单看 teaCup 这个变量,它的类型是 Cup<? extends Tea>,我们并不知道这个里面放的具体是 Tea、GeeenTea 还是 BlackTea,那么我们在调用 setT() 方法时无论传什么实例进去都会报错(假设定义时的 T 是 GreenTea,setT() 传入的是 BlackTea 必定报错)
//都会报错
teaCup.setT(new Tea());
teaCup.setT(new GreenTea());
teaCup.setT(new BlackTea());
同时调用 get() 方法的值只能用上界去接收,因为无论里面是红茶、绿茶它都是“茶”
Tea tea = teaCup.getT()
于是非常神奇的事情出现了,这个 teaCup 就变成了一个只能 get 不能 set 的一个茶杯
所以我们得出结论:
上界 <? extends T> 不能往里存,只能往外取
现在我们再定义几个类
public class Drinks {}
public class Tea extends Drinks {}
public class Coffee extends Drinks {}
public class Latte extends Coffee {}
public class Mocha extends Coffee {}
<? extends T> 表示的就是
现在再来看下界通配符 <? super T>,它表示的是 T 或者 T 的所有父类
先说结论
下界 <? super T> 可以往里存,往外取只能用 Object 接收
因为往外取的时候不能确定具体的类型,所以无法用 Tea 或者 Drinks 来接收,乍一看上图能用 Drinks 来接收,实则不能(若 Drinks 有父类),所以只能用最顶端的父类 Object 来接收
往里存的时候只能存 Tea 以及 Tea 的子类,因为下界规定了元素最小粒度的下限,所以无论是 Tea、GreenTea、BlackTea 都是茶(Tea),也都是饮品(Drinks),所以往里存没有问题
PECS原则
PECS(Producer Extends Consumer Super)原则
- 频繁往外读取的,适合用上界 extends
- 频繁往里插入的,适合用下界 super