<? extends T> 和 <? super T> 是Java泛型中的“通配符(Wildcards)” 和 “边界(Bounds)”
<? extends T> 是指 “
上界通配符
”
<? super T> 是指 “
下界通配符
”
1、
public class Vehicle {
Auto4SStores<Car> as = new Auto4SStores<Vehicle>();
}
class AutoS4Stores<T>{
private T item;
public T get(){
return item;
}
public void set(T item){
this.item = item;
}
}
class Car extends Vehicle{}
class Audi extends Car{}
class Toyota extends Car{}
class Lexus extends Car{};
class Avalon extends Toyota{}
如上图,Audi是一种车(Car),但是4S店不一定是卖Audi的4S店,有可能是丰田(Toyota)的,等等,
所以Auto4SStores<Car> 并不认识Auto4SStores<Audi>,
public class Vehicle {
Auto4SStores<? extends Car> as = new Auto4SStores<Audi>();
}
于是,
上界通配符 <? extends T>
的作用就体现出来了,
为什么叫上界通配符呢,可以理解为 ?继承(extends)自T或者T的派生类。Car类是所有泛型的上界。
而
下界通配符<? super T>
public class Vehicle {
Auto4SStores<? super Car> as = new Auto4SStores<Vehicle>();
}
Car是三角区域的下边界,这里可以理解为 ?超类(super)Car,意思就是?是Car的超类,Car是泛型的最下边界
2、
上界通配符
<? extends T>不能往里存,只能往外取
(1).<? extends Car>会使往盘子里放东西的set( )方法失效,但取东西get( )方法还有效
(2).取出来的东西只能存放在Car或它的基类里面,向上造型。
编译器只知道容器内是Car或者它的派生类,但具体是什么类型不知道,因此取出来的时候要向上造型为基类。
可能是Car,可能是Audi,也可能是Toyota或者子品牌凯美瑞,奥迪A4等等,编译器在看到后面用AutoStores<Audi>赋值以后,4S店里没有被标上是奥迪4S店还是丰田4S店。而是标上一个占位符:capture#1,来表示捕获一个Car或Car的子类,具体是什么类不知道,代号capture#1。
然后无论想进货一辆奥迪A4还是丰田汉兰达或者雷克萨斯ES编译器都不知道能不能和这个capture#1匹配,所以就都不允许。
下界通配符
<? super T>可能往里存,但往外取数据只能放到基类Object里面
因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制
既然元素是Car的基类,那往里存粒度比Car小的都可以。
但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失。
3、 PECS原则
Producer extends: 生产者确定上界 ,用extends
Consumer super: 消费者确定下界,用super
什么意思呢?
如果AutoStores代表一个生产者,那么泛型就可以用<? extends T>表示,生产者生产的数据是供我们读取消费的
如果AutoStores代表一个消费者,那么泛型就可以用<? super T>表示,因为我们需要往里面存数据供AutoStores去消费