E – Element (在集合中使用,因为集合中存放的是元素)

T – Type(Java 类)

K – Key(键)

V – Value(值)

N – Number(数值类型)

? – 表示不确定的java类型(无限制通配符类型)

S、U、V – 2nd、3rd、4th types

Object – 是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。

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

Java的类型擦除我们提到过:类型擦除中第一步——将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
这里的左边届可以通过extends来体现。

当生成泛型类的字节码时,编译器用类型参数的擦除替换类型参数。对于无限制类型参数 (),它的擦除是 Object。对于上限类型参数(>),它的擦除是其上限(在本例中是 Comparable)的擦除。对于具有多个限制的类型参数,使用其最左限制的擦除。

extends

上界用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。

比如,我们现在定义:List<? extends T>首先你很容易误解它为继承于T的所有类的集合,你可能认为,你定义的这个List可以用来put任何T的子类,那么我们看一下下面的代码:

import java.util.LinkedList;
import java.util.List;
/**
* @author hollis
*/
public class testGeneric {
public static void main(String[] args) {
List<? extends Season> seasonList = new LinkedList<>();
seasonList.add(new Spring());
}
}
class Season{
}
class Spring extends Season{
}

seasonList.add(new Spring());这行会报错:The method put(Spring) is undefined for the type List<capture#1-of ? extends Season>

List<? extends Season> 表示 “具有任何从Season继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List 赋值。
你也许试图这样做:

List<? extends Season> seasonList = new LinkedList<Spring>();
seasonList.add(new Spring());

但是,即使指明了Spring,也不能用add方法添加一个Spring对象。

list中为什么不能加入Season类和Season类的子类呢,原因是这样的:

List<? extends Fruit>表示上限是Fruit,下面这样的赋值都是合法的

   List<? extends Season> list1 = new ArrayList<Season>();
List<? extends Season> list2 = new ArrayList<Spring>();
List<? extends Season> list3 = new ArrayList<Winter>();

如果List<? extends Season>支持add方法的方法合法的话
list1可以add Season和所有Season的子类
list2可以add Spring和所有Spring的子类
list3可以add Winter和所有Winter的子类

这样的话,问题就出现了

List<? extends Season>所应该持有的对象是Season的子类,而且具体是哪一个子类还是个未知数,所以加入任何Season的子类都会有问题,
因为如果add Spring的话,可能List<? extends Season>持有的对象是new ArrayList()
Spring的加入肯定是不行的,如果 如果add Winter的话,可能List<? extends Season>持有的对象是new ArrayList<Jonathan的子类>()
Winter的加入又不合法,所以List<? extends Season> list 不能进行add

但是,这种形式还是很有用的,虽然不能使用add方法,但是可以在初始化的时候一个Season指定不同的类型。比如:
List<? extends Season> list1 = getSeasonList();//getSeasonList方法会返回一个Season的子类的list

另外,由于我们已经保证了List中保存的是Season类或者他的某一个子类,所以,可以用get方法直接获得值:

List<? extends Season> seasonList = new LinkedList();
Spring spring = (Spring) seasonList.get(0);
Season season = seasonList.get(1);

super

下界用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object。

如:

List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> = fruits;
fruits.add(new Apple()); //work
fruits.add(new RedApple()); //work
fruits.add(new Fruit()); //compile error
fruits.add(new Object()); //compile error

这里的fruits是一个Apple的超类(父类,superclass)的List。同样地,出于对类型安全的考虑,我们可以加入Apple对象或者其任何子类(如RedApple)对象,但由于编译器并不知道List的内容究竟是Apple的哪个超类,因此不允许加入特定的任何超类型。

而当我们读取的时候,编译器在不知道是什么类型的情况下只能返回Object对象,因为Object是任何Java类的最终祖先类。

PECS原则

如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
如果既要存又要取,那么就不要使用任何通配符。

参考资料:

Java泛型中的PECS原则

http://www.hollischuang.com/archives/255

Java泛型中extends和super的理解(转)的更多相关文章

  1. Java泛型中extends和super的理解

    作者:zhang siege链接:https://www.zhihu.com/question/20400700/answer/91106397来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...

  2. java泛型中extends 和 super的区别

    一般对泛型中extends 和 super 的区别是这样介绍的: 关键字说明 ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类 < ...

  3. Java泛型中extends和super的区别?

    <? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概念. ...

  4. 浅谈Java泛型之<? extends T>和<? super T>的区别

    关于Java泛型,这里我不想总结它是什么,这个百度一下一大堆解释,各种java的书籍中也有明确的定义,只要稍微看一下就能很快清楚.从泛型的英文名字Generic type也能看出,Generic普通. ...

  5. JAVA泛型知识--> <? extends T>和<? super T>

    <? extends T> 和 <? super T> 是Java泛型中的“通配符(Wildcards)” 和 “边界(Bounds)”的概念 <? extends T& ...

  6. JAVA 泛型 通配符? extends super限定,实例区分extends super限定的作用用法

    java泛型中的关键字 ? 表示通配符类型 <? extends T> 既然是extends,就是表示泛型参数类型的上界,说明参数的类型应该是T或者T的子类. <? super T& ...

  7. Java泛型中<?> 和 <? extends Object>的异同分析

    相信很多人和我一样,接触Java多年,却仍旧搞不清楚 Java 泛型中 <?>和 <? extends Object>的相似和不同.但是,这应该是一个比较高端大气上档次的Que ...

  8. 大白话说Java泛型(二):深入理解通配符

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型(二):深入理解通配符> 上篇文章<大白话说Java泛型(一):入门.原理.使用>,我们讲了泛型的产生缘由以及 ...

  9. Java泛型中的细节

    Java泛型中的细节 如果没有泛型 学习Java,必不可少的一个过程就是需要掌握泛型.泛型起源于JDK1.5,为什么我们要使用泛型呢?泛型可以使编译器知道一个对象的限定类型是什么,这样编译器就可以在一 ...

随机推荐

  1. java输出换行的标准姿势"line.separator"

    java中写.txt文件,实现换行的几种方法: 1.使用java中的转义符"\r\n": windows下的文本文件换行符:\r\n linux/unix下的文本文件换行符:\r ...

  2. 2014年Windows平台软件推荐:神器小工具(骨灰级

    原文  http://www.wtoutiao.com/a/120621.html 底层工具 “If you know how to use Process Monitor competently, ...

  3. delphi cmd(4个例子都是通过管道取得)

    //K8执行DOS并返回结果 function RunDosCommand(Command: string): string; var hReadPipe: THandle; hWritePipe:  ...

  4. 简单深刻:为控件创建MouseEnter和MouseLeave事件(覆盖WndProc,增加对消息的处理,真简单!)——连对CM_MOUSEENTER的消息处理都是颇有深意啊!

    其实很简单: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, D ...

  5. java中Hashtable中的t为什么是小写(转)

    因为在很多年前刚学java的时候用到Hashtable的时候比较好奇为什么第二个t是小写,这不符合sun的风格啊,整个jdk都是标准驼峰,于是带着这个疑问翻过 很多书,看多很多资料,最后的结论是: H ...

  6. Android中使用SurfaceView和Canvas来绘制动画

    事实上每一个View中都有Canvas能够用来绘制动画.仅仅须要在这个View中重载onDraw()方法就能够,可是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做&quo ...

  7. 【Cocos2d-X开发学习笔记】第01期:PC开发环境的详细搭建

    本文使用的是cocos2d-x-2.1.4版本 ,截至目前为止是最新稳定版 所谓的开发环境就是制作游戏的地方,打个比方读者就会十分清楚了.比如提到做饭,人们都会想到厨房.这是 因为厨房有炉灶.烟机.水 ...

  8. DS Scheduler 0.7 发布,Linux 调度系统 - 开源中国社区

    DS Scheduler 0.7 发布,Linux 调度系统 - 开源中国社区 DS Scheduler 0.7 发布,Linux 调度系统

  9. linux在下面APK反编译软件和过程的描述

    需要的工具: 1.apktool apk打包工具 下载地址:http://android-apktool.googlecode.com/files/apktool1.5.2.tar.bz2 安装:直接 ...

  10. 【iOS】苹果,百度Map定位使用与总结

    iOS中使用较多的3款地图,google地图.百度地图.苹果自带地图(高德).当中苹果自带地图在中国使用的是高德的数据.苹果在iOS 6之后放弃了使用谷歌地图,而改用自家的地图.在国内使用的较多的就是 ...