List<? extends T>和List<? super T>之间有什么区别?

<? extends T>表示类型的上界,也就是说,参数化的类型可能是T或者T的子类。例如,下面的写法都是合法的赋值语句:、

List<? extends Number> list = new ArrayList<Number>();
List<? extends Number> list = new ArrayList<Integer>(); //Integer是Number的子类
List<? extends Number> list = new ArrayList<Float>();	//Float也是Number的子类

<? extends T>被设计为用来读数据的泛型(只能读取类型为T的元素),原因如下:

(1)在上面赋值的示例中,对读数据进行分析

1)不管给list如何赋值,可以保证list里面存放的一定是Number类型或其子类,因此,可以从list列表里面读取Number类型的值。

2)不能从list中读取Integer,因此list里面存放的是Float值,同理,也不可以从list里面读取Float。

(2)对写数据进行分析

1)不能向list中写Number,因为list中有可能存放的是Float。

2)不能向list中写Integer,因为list中有可能存放的是Float。

3)不能向list中写Float,因为list中有可能存放的是Integer。

从上面的分析可以发现,只能从List<? extends T>读取T,因为无法确定它实际指向列表的类型,从而无法确定列表里面存放的实际的类型,所以,无法向列表里面添加元素。

<? super T>表示类型下界,也就是说,参数化的类型是此类型的超类型(父类型)。

List<? super Float> list = new ArrayList<Float>();
List<? super Float> list = new ArrayList<Number>();	//Number是Float的父类
List<? super Float> list = new ArrayList<Object>();	//Float也是Number的子类

<? super T>被设计为用来写数据的泛型(只能写入T或T的子类类型),不能用来读,分析如下

(1)读数据

无法保证list里面一定存放的是Float类型或者Number类型,因为有可能存放的是Object类型,唯一能确定的是list里面存放的是Object或其子类,但是无法确定具体子类的类型。

正是由于无法确定list里面存放数据的类型,因此,无法从list里面读取数据。

(2)写数据

1)可以向list里面写入Float类型的数据(不管list里面实际存放的是Float,Number或者Object,写入Float都是允许的);同理,也可以向list里面添加Float子类类型的元素。

2)不可以向list里面添加Number或Object类型的数据,因为list中可能存放的是Float类型的数据。

下面给出两个泛型使用的场景

 public static <T> void copy(List<? super T> dest,List<? extends T> src){
        for (int i = 0; i < src.size(); i++) {
            dest.set(i,src.get(i));
        }
    }
posted @ 2022-01-02 19:53  杜嘟嘟  阅读(467)  评论(0编辑  收藏  举报