泛型通配符之PECS

目录

基础知识点

上限通配符 

List中上限通配符的add()方法

List中上限通配符的get()方法

下限通配符

List中下限通配符的add()方法

List中下限通配符的get()方法


基础知识点

        开始先了解一下基础知识点:

        在Java中,向上转型是允许的,但向下转型会无法编译通过。如果强转,有可能会抛出ClassCastException异常。那么如果真要向下转型,平时我们要一般都会先用instanceof来判断是否是这个类型,如果是,才进行强转。

        废话不多说,上代码:

class A {
}

class B extends A {
}

class C extends B {
}

上限通配符 

        上限通配符:? extends B  ,表示某类型的父类是B(或者说,某类型继承于B),它和类的extend是一样的。

List中上限通配符的add()方法

        它负责放入一个某种类型的对象到List中。在下面这个代码块代码中,这个某种类型肯定是B的子类类型。

List extendList = new ArrayList<>();
extendList.add(new Object());//编译报错
extendList.add(new A());//编译报错
extendList.add(new B());//编译报错
extendList.add(new C());//编译报错
extendList.add(null); //可以放入,因为null不是有效的对象实例。

        为什么除了add(null),其它的都不能通过编译呢?
        因为编译器只知道extendList应该放入B的子类,但并不知道放B的哪个子类。也就是说如果B有1万个子类,某种类型就有1万种类型的可能,这个时候没办法判断它具体是那个类型。由于编译器不懂是B的哪个子类,在执行add方法时,无法进行类型转换成某个指定的类放入List,所以只能放入null,而不能放入其它的对象。
        有人可能会说为啥Object也不行?因为Object是所有类的父类,但是由于向下转型正常也是编译不通过的,所以也不能放入。

List中上限通配符的get()方法

        它负责从某种类型的List方法中返回某种类型的值。在下面这个代码块中,这个某种类型是B的子类型,加上在java中向上转型是允许的,所以可以返回类型为B及其父类型的值(例如:A类型,以及所有类的父类Object)。但是编译器依旧不能确定是B类型的哪个子类,所以就算B类型只有一个子类C,也不能直接返回C类型的对象(除非强转)。

注:它就是PECS中的PE,即produce  ->  extend  ,下面代码中表示List是生产者,你只能从这个List里面往外面拿(给别人)。

List extendList = new ArrayList<>();
B b = extendList.get(0);//正常
A a = extendList.get(0);//正常向上转型
C c = extendList.get(0);//编译报错

下限通配符

        下限通配符:? super B  ,表示某类型是B的父类型,和代码中调用父类方法的super关键字类似。

List中下限通配符的add()方法

        它负责放入一个某种类型的对象到List中。在下面这个代码块代码中,这个某种类型肯定是B的父类类型。

        注:它就是PECS中的CS,即consumer  ->  super ,下面代码中表示这个List集合是消费者,你只能往里面放(给它消费)。

List superList = new ArrayList<>();
superList.add(new Object());//编译报错
superList.add(new A());//编译报错
//某种类型肯定是B的父类型,所以只能放入B或B的子类,才能向上转型
superList.add(new B());
superList.add(new C());
superList.add(null); //可以放入,因为null不是有效的对象实例。

        为什么这个List可以执行add方法呢?
        虽然编译器可以知道B的所有父类,但是它也没法知道这个某种类型具体是B的哪一个父类类型,所以你可以放入B及B的子类型(向上转型)。

List中下限通配符的get()方法

        因为编译器不懂返回的是什么类型,只知道是B类型的父类,所以只能返回一个Object(因为它是所有类的父类)。

Object object = superList.get(0);//正常
A a1 = superList.get(0);//编译报错
B b1 = superList.get(0);//编译报错
C c1 = superList.get(0);//编译报错
 

你可能感兴趣的:(Java基础)