java基础-泛型中的extends和super

List<Number> numbers = new ArrayList<Integer>();

java的ArrayList有一个这样的构造函数

    public ArrayList(Collection<? extends E> c) {
      .......
    }

在不知道extends的作用的前提下,我们日常使用中就已经明白了这个构造函数的意思是传入一个Collection类型的集合,里面包含了我们声明的元素或者其子元素
用代码来说就是:

    ArrayList<Integer> integers = new ArrayList<>();
    ArrayList<Double> doubles = new ArrayList<>();
    new ArrayList<Number>(integers);
    new ArrayList<Number>(doubles);

想在已有的List的基础上去创建一个包含Number的List,因为是包含Number的集合,所以理论上我我可以传入List<Integer>,List<Double>这样的包含任一Number的子类的List。如果不去看源码的情况下,我们可能会很理想化的想到,ArrayList的这个构造函数是这样的:

public ArrayList(Collection<E> c) { ....... }

代表我可以传入List<Integer>,List<Double>。然而并不是。
因为在java里面,
List<Number> list = new ArrayList<Integer>();
所以有了extends。

    List<? extends Number> list;
    list = new ArrayList<Number>();
    list = new ArrayList<Integer>();
    list = new ArrayList<Double>();

以上便是extends的作用,它表示声明的这个list 可以被赋予任何一种包含Number和Number子类的list
因为被赋予的List包含的必定是Number的子类,所以读出来的元素不论原本是Integer,Double,还是任一Number的子类,都可以像上转型为Number,所以下面的代码是没问题的。

Number item = list.get(0);

但是,当你add的时候,因为被赋予有可能是new ArrayList<Integer>() ,new ArrayList<Double>()这些List中的任一一个,光靠声明的信息JVM在编译的时候是不知道具体是哪个list,那么你就不能往里面加元素。因为如果是赋予的一个new ArrayList<Integer>(),而你add的是一个Double,那岂不是违反了泛型的基本语法,不允许不同类型的元素放入泛型容器中。

list.add(??????);

所以,当在声明的时候使用了extends,那么List就只能get,不能add了。
也即 extends 表示此list只能读。

super,同样的Demo:

    List<? super Double> list;
    list = new ArrayList<Double>();
    list = new ArrayList<Number>();
    list = new ArrayList<Object>();

上面这代码表示list表示可以被赋予任意一个装有Double或Double父类的list;
同理
读:
???? item = list.get(0);
这样是不行的,为啥?因为这个list是可能被赋予的list太广了。
如果是List<? super Double> list = new ArrayList<Object>();
那怎么可能知道你读出来的会是什么玩意儿?
写:

 list.add(new Double(1));

为啥这里可以写入呢?
因为不论赋予的是以下3种的任一一种集合,反正都是最少都是装Double的,所以一定可以装入Double,那么写入是可以的。

    list = new ArrayList<Double>();
    list = new ArrayList<Number>();
    list = new ArrayList<Object>();

所以使用了super的list没法读取,只能写入。

结合extends和super的特性,总结出来就是:PECS(Producer Extends, Consumer Super)

参考link:https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,877评论 18 399
  • 开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收List作为形式参数,那么如果尝试...
    时待吾阅读 1,083评论 0 3
  • 前言 泛型(Generics)的型变是Java中比较难以理解和使用的部分,“神秘”的通配符,让我看了几遍《Java...
    珞泽珈群阅读 7,993评论 12 51
  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 2,083评论 0 3
  • shake,tremble,shiver,quiver,vibrate,shudder这些动词均含“震动,颤抖”之...
    keaidelele阅读 3,362评论 0 50