Java编程思想:关于Java中 ? extends T 和 ? super T 的理解

?通配符类型

  • <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类;(上界通配符)
  • <? super T> 表示类型下界,表示参数化类型是此类型的超类型(父类型),直至Object;(下界通配符)

上界通配符<? extends T>不能往里存,只能往外取

public class test {
    public static void main(String[] args) {
        List<Class<? extends pet>> list = new LinkedList<Class<? extends pet>>();
        list.add(new dog());
    }
}
class pet {

}
class dog extends pet {

}
class cat extends dog {

}

list.add(new dog())表示 “具有任何从dog继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。

List<? extends pet> list = new LinkedList<dog>();
list.add(new dog());

即使你指明了dog的类型,也不能用add方法添加一个dog对象

假设支持add()方法

   List<? extends pet> list1 = new ArrayList<pet>();
   List<? extends pet> list2 = new ArrayList<dog>();
   List<? extends pet> list3 = new ArrayList<cat>();

如果List<? extends pet>支持add方法的话:

  • list1可以add pet和所有pet的子类;
  • list2可以add dog和所有dog的子类;
  • list3可以add cat和所有cat的子类;
    下面的代码我们是编译不能通过的:
list.add(new pet());//error
list.add(new dog());//error

原因:编译器只知道容器内是pet或者它的派生类,但具体是什么类型不知道。可能是pet?可能是dog?也可能是cat?编译器在看到后面用pet赋值以后,集合里并没有限定参数类型是“pet“.

所以通配符<?>和类型参数的区别就在于,对编译器来说所有的T都代表同一种类型。比如public <T> List<T> fill(T... t)这个泛型方法里,三个T都指代同一个类型,要么都是String,要么都是Integer。

所以这里的错误就在这里,List<? extends pet>里什么都放不进去。
List<? extends pet> list不能进行add,但是,这种形式还是很有用的,虽然不能使用add方法,但是可以在初始化的时候一个Season指定不同的类型。比如:

List<? extends pet> list1 = getPetList();//getPetList方法会返回一个pet的子类的list

另外,由于我们已经保证了List中保存的是Pet类或者他的某一个子类,所以,可以用get方法直接获得值:

List<? extends pet> list1 = new ArrayList<>();
Pet pet = list1.get(0);//读取出来的东西只能存放在pet或它的基类里。
Object object = list1.get(0);//读取出来的东西只能存放在pet或它的基类里。
Dog dog= list1.get(0);//读取出来的东西只能存放在pet或它的基类里。

下界<? super T>不影响往里存,但往外取只能放在Object对象里

PECS原则

  • 频繁往外读取内容的,适合用上界Extends
  • 经常往里插入的,适合用下界Super
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值