【JAVA】List( ? extends T )与List( ? super T)的区别

版权声明:转载请注明 https://blog.csdn.net/qq_33591903/article/details/82746794

                        List<? extends T>与List<? super T>的区别

ps:标题中的圆括号应该为尖括号,否则,标题非法,发表不出去。


一、前置名次解释

(1)?

?表示类型通配符,即具体传什么参数类型,在List定义时不用考虑。

(2)<T>

这里的<>表示泛型,T表示泛型中装载的类型为T类型,等到需要的时候,我们可以具体这个T。我们在使用动态数组实现ArrayList的时候,如果希望这个ArrayList不仅仅支持一个类型的话,我们可以给这个ArrayList定义泛型,泛型中存放的是T类型。在实际创建出这个ArrayList对象时,我们可以指定泛型中的具体类型。

(3)<? extends T>

类型上界。表示的是此处我们传入的类型必须是T类型本身或其子类。如果这里的T为Number的话,那么我们只能传入Number本身或其子类,比如Integer,Floart等基本数据类型的包装类。

(4)<? super T>

类型下界。表示的是此处我们传入的类型必须是T类型本身或其超类。如果这里的T为Integer的话,那么我们只能传入Integer本身或其超类,比如Number类。


二、List<? extends T>

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

我们现在知道,此List中存放的都是T类型或其子类,因此,我们可以这样做来读取元素。

   List<? extends Number> list = new ArrayList<>(); 
   Number number=list.get(0);

使用Number类型,即T类型来接受本身类型或其子类类型的元素。

当然这样的赋值也是合法的

   List<? extends Number> integers = new ArrayList<Integer>();
   List<? extends Number> floats = new ArrayList<Float>();

他为什么不能增加元素?原因如下:

编译器仅仅通过List<? extends Number>来了解到,这个List中可以存放Number本身和其子类,但具体是什么它不知道,即使在等号后面使用new ArrayList<Integer>(),编译器仍然不为所动,它就是不知道该存什么类型,那么,这种泛型,就不能用来临时add元素。

但是!虽然不能add元素,但可以在初始化的时候,接受一个已经定义好的list,而该list存放的类型一定相同,因此,List<? extends T>可直接接受一个定义好的list。

 public static List<Integer> getList(){
        List<Integer> list=new ArrayList<>();
        list.add(1);
        return list;
    }

....

    public static void main(String[] args) {
        List<? extends Number> list = new ArrayList<>();
        list=getList();
    }

三、List<? super T>

List<? super T>是被设计用来添加数据的泛型,并且只能添加T类型或其子类类型的元素。

我们知道,此List中存放的元素一定是T类型或其父类类型的元素,由于编译器不确定到底是什么类型,我们可以这样来添加元素。

  List<? super Integer> list2 = new ArrayList<>();
        list2.add(new Integer(1));
        list2.add(new Double(1.0));//编译错误,Double不为Integer的子类

由于编译器不知道我们需要什么类型,因此在获取元素的时候,总是返回Object类型,因此我们使用Object类型来接受获取到的元素。

   List<? super Integer> list2 = new ArrayList<>();
   list2.add(new Integer(1));
   Object integer=list2.get(0);

如果我们非要使用List<? super Integer>中的Integer类型来接收获取到的元素,那么必须进行强制类型转换。

   List<? super Integer> list2 = new ArrayList<>();
   list2.add(new Integer(1));
   Integer integer1= (Integer) list2.get(0);

如果我们使用Object类型来接收获取到的元素,那么元素本身的类型就会丢失,因此,我们不使用List<? super T>来获取元素。


四、总结

(1)List<? extends T>适用于读取数据,读取出来的数据全部用T类型接收。如果我们往此list中添加T类型不同的子类的话,各种子类无法相互转换,因此不能添加元素,但可接受初始赋值。

(2)List<? super T>适用于添加元素,只能添加T类型或其子类类型。因为这些类型都能转换为?表示的类型(向上转型),因此我们可以对此list添加元素。只能用Object类型来接收获取到的元素,但是这些元素原本的类型会丢失,因此最好不要使用此泛型来获取元素。

猜你喜欢

转载自blog.csdn.net/qq_33591903/article/details/82746794
今日推荐