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

原创 2017年09月07日 16:13:56

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》
版权声明:本文为博主原创文章,未经博主允许不得转载。

泛型中? super T和? extends T的区别

  • 2015年12月17日 10:34
  • 374KB
  • 下载

Java 泛型中? super T和? extends T的区别

经常发现有List、Set的声明,是什么意思呢?表示包括T在内的任何T的父类,表示包括T在内的任何T的子类,下面我们详细分析一下两种通配符具体的区别。 extends List foo3的...

java泛型中<? super T> 和<? extends T>的区别---转发

java泛型中

泛型中? super T和? extends T的区别

原文出处: 并发编程网 经常发现有List、Set的声明,是什么意思呢?表示包括T在内的任何T的父类,表示包括T在内的任何T的子类,下面我们详细分析一下两种通配符具体的区别。 extends Lis...

Java 泛型 <? super T> 中 super 怎么 理解?与 extends 有何不同?

题主说的和是Java泛型中的“通配符(Wildcards)”和“边界(Bounds)”的概念。 :是指 “上界通配符(Upper Bounds Wildcards)”:是指 ...

Java 泛型 <? super T> 中 super 怎么 理解<?与 extends> 有何不同?

Java 泛型 中 super 怎么 理解 有何不同? 问题引入: // compile error // List appList2 = new ArrayList();...
  • lswlov
  • lswlov
  • 2016年11月26日 17:33
  • 691

Java学习之道:简述泛型通配符<? extends T>和<? super T>

和含有JAVA5.0的新的概念。由于它们的外表导致了很多人误解了它们的用途: 1.首先你很容易误解它为继承于T的所有类的集合,这是大错特错的,相信能看下去你一定见过或用过List吧?为什么我说理...

Java中<? extends T>和<? super T>的理解,泛型的使用规则

? 通配符类型 - T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类; T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Objec...

Java泛型中<T extends Comparable<? super T>>是什么意思

原文地址:Java泛型中。。。啥意思啊

泛型中super和extends的用法及区别

泛型是在Java 1.5中被加入了,这里不讨论泛型的细节问题,这个在Thinking in Java第四版中讲的非常清楚,这里要讲的是super和extends关键字,以及在使用这两个关键字的时候为什...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:泛型<?super T> 和<? extends T>区别
举报原因:
原因补充:

(最多只允许输入30个字)