JAVA泛型之<? extends T>和<? super T>

  • Post author:
  • Post category:java


<? 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去消费



版权声明:本文为qq_15125423原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。