关闭

泛型<?super T> 和<? extends T>区别

标签: super T 和 extends T区
53人阅读 评论(0) 收藏 举报
分类:

Java 泛型

关键字说明
  • ? 通配符类型
  • <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类
  • <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object
首先,泛型的出现时为了安全,所有与泛型相关的异常都应该在编译期间发现,因此为了泛型的绝对安全,java在设计时做了相关的限制:List<? extends E>表示该list集合中存放的都是E的子类型(包括E自身),由于E的子类型可能有很多,但是我们存放元素时实际上只能存放其中的一种子类型(这是为了泛型安全,因为其会在编译期间生成桥接方法<Bridge Methods>该方法中会出现强制转换,若出现多种子类型,则会强制转换失败),
例子如下:
List<? extends Number> list=new ArrayList<Number>();
list.add(4.0);//编译错误
list.add(3);//编译错误
上例中添加的元素类型不止一种,这样编译器强制转换会失败,为了安全,Java只能将其设计成不能添加元素。虽然List<? extends E>不能添加元素,但是由于其中的元素都有一个共性--有共同的父类,因此我们在获取元素时可以将他们统一强制转换为E类型,我们称之为get原则。对于List<? super E>其list中存放的都是E的父类型元素(包括E),我们在向其添加元素时,只能向其添加E的子类型元素(包括E类型),这样在编译期间将其强制转换为E类型时是类型安全的,因此可以添加元素,
例子如下:
List<? super Number> list=new ArrayList<Number>();
list.add(2.0);
list.add(3.0);
但是,由于该集合中的元素都是E的父类型(包括E),其中的元素类型众多,在获取元素时我们无法判断是哪一种类型,故设计成不能获取元素,我们称之为put原则。实际上,我们采用extends,super来扩展泛型的目的是为了弥补例如List<E>只能存放一种特定类型数据的不足,将其扩展为List<? extends E> 使其可以接收E的子类型中的任何一种类型元素,这样使它的使用范围更广。
List<? super E>同理。

extends示例:

static class Food{}
static class Fruit extends Food{}
static class Apple extends Fruit{}
static class RedApple extends Apple{}

List<? extends Fruit> flist = new ArrayList<Apple>();
// complie error:
// flist.add(new Apple());
// flist.add(new Fruit());
// flist.add(new Object());
flist.add(null); // only work for null 
List<? extends Frut> 表示 “具有任何从Fruit继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List<Apple> 赋值。
Fruit fruit = flist.get(0);
Apple apple = (Apple)flist.get(0);
由于,其中放置是从Fruit中继承的类型,所以可以安全地取出Fruit类型。
flist.contains(new Fruit());
flist.contains(new Apple());
在使用Collection中的contains 方法时,接受Object 参数类型,可以不涉及任何通配符,编译器也允许这么调用。

super示例:

List<? super Fruit> flist = new ArrayList<Fruit>();
flist.add(new Fruit());
flist.add(new Apple());
flist.add(new RedApple());

// compile error:
List<? super Fruit> flist = new ArrayList<Apple>();
List<? super Fruit> 表示“具有任何Fruit超类型的列表”,列表的类型至少是一个 Fruit 类型,因此可以安全的向其中添加Fruit 及其子类型。由于List<? super Fruit>中的类型可能是任何Fruit 的超类型,无法赋值为Fruit的子类型Apple的List<Apple>.
// compile error:
Fruit item = flist.get(0);
因为,List<? super Fruit>中的类型可能是任何Fruit 的超类型,所以编译器无法确定get返回的对象类型是Fruit,还是Fruit的父类Food 或 Object.

小结:

  • extends 可用于的返回类型限定,不能用于参数类型限定。
  • super 可用于参数类型限定,不能用于返回类型限定。
  • >带有super超类型限定的通配符可以向泛型对易用写入,带有extends子类型限定的通配符可以向泛型对象读取。——《Core Java》

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:89977次
    • 积分:1844
    • 等级:
    • 排名:千里之外
    • 原创:90篇
    • 转载:37篇
    • 译文:4篇
    • 评论:12条
    最新评论