泛型中的extends和super的区别

来源:互联网 发布:开发sql语句美化小工具 编辑:程序博客网 时间:2024/05/17 08:56

在网上看到如下代码,不知道为什么报错,代码如下:

public class GenericTest {        public static void main(String[] args) throws Exception {           List<? super Fruit> f0=new ArrayList<Fruit>();         f0.add(new Apple());         f0.add(new Fruit());         f0.add(new SupApple());                  List<? super Fruit> f1=new ArrayList<Apple>();         f1.add(new Apple());         f1.add(new Fruit());                  List<? extends Fruit> f2=new ArrayList<Fruit>();         f2.add(new Apple());         f2.add(new Fruit());                   List<? extends Fruit> f3=new ArrayList<Apple>();         f3.add(new Apple());         f3.add(new Fruit());                   List<? super Apple> f5=new ArrayList<Fruit>();         f5.add(new Apple());         f5.add(new SupApple());         f5.add(new Fruit());      }  }   class Fruit{  }  class Apple extends Fruit{  }   class SupApple extends Apple{      } 


首先说下extends和super的却别(参考:点击打开链接):

extends

List<? extends Number> foo3的通配符声明,意味着以下的赋值是合法的:

List<? extends Number> foo3 = new ArrayList<? extends Number>();

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

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

  1. 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素。

    你不能保证读取到Integer,因为foo3可能指向的是List<Double>。

    你不能保证读取到Double,因为foo3可能指向的是List<Integer>。

  2. 写入操作过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?

    你不能插入一个Integer元素,因为foo3可能指向List<Double>。

    你不能插入一个Double元素,因为foo3可能指向List<Integer>。

    你不能插入一个Number元素,因为foo3可能指向List<Integer>。

    你不能往List<? extends T>中插入任何类型的对象,因为你不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。

super

现在考虑一下List<? super T>。

List<? super Integer> foo3的通配符声明,意味着以下赋值是合法的:

List<? super Integer> foo3 = new ArrayList<Integer>();

List<? super Integer> foo3 = new ArrayList<Number>();

List<? super Integer> foo3 = new ArrayList<Object>();

  1. 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你不能保证读取到Integer,因为foo3可能指向List<Number>或者List<Object>。

    你不能保证读取到Number,因为foo3可能指向List<Object>。

    唯一可以保证的是,你可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。

  2. 写入操作通过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?你可以插入Integer对象,因为上述声明的列表都支持Integer。

    你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。

    你不能插入Double对象,因为foo3可能指向ArrayList<Integer>。

    你不能插入Number对象,因为foo3可能指向ArrayList<Integer>。

    你不能插入Object对象,因为foo3可能指向ArrayList<Integer>。

通过网上查找,最终明白了:

public static void main(String[] args) throws Exception {      //定义正确,使用正确。List<? super Fruit> f0 = new ArrayList<Fruit>();f0.add(new Apple());f0.add(new Fruit());f0.add(new SupApple());List<? super Fruit> f1 = new ArrayList<Apple>(); // ArrayList泛型中的只能是Fruit或者Object,即Fruit本身或者Fruit的父类类型。f1.add(new Apple());f1.add(new Fruit());//定义正确,使用错误。List<? extends Fruit> f2 = new ArrayList<Fruit>();//添加了Apple,f2有可能指向ArrayList<SupApple>f2.add(new Apple());//添加了Fruit,f2有可能指向ArrayList<SupApple>/ArrayList<Apple>f2.add(new Fruit());//定义正确,使用错误。List<? extends Fruit> f3 = new ArrayList<Apple>();//添加了Apple,f3有可能指向ArrayList<SupApple>f3.add(new Apple());//添加了Apple,f3有可能指向ArrayList<SupApple>/ArrayList<Apple>f3.add(new Fruit());//只能添加Apple以及Apple的子类List<? super Apple> f5 = new ArrayList<Fruit>();f5.add(new Apple());f5.add(new SupApple());f5.add(new Fruit());/** * 总结: * extends,只能读取,不能写。 * super:可以读取,且只能返回Object类型,或Object的子类对象(但是不能确定具体的子类是什么) *       可以写,? super Xxx ,只能写Xxx或Xxx的子类对象。 */    }  



0 0
原创粉丝点击