文档章节

java泛型中,上下界通配符(<? extends T>跟<? super T>)

贺小五
 贺小五
发布于 2017/01/08 02:10
字数 1862
阅读 1143
收藏 39

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

背景介绍:java中的泛型,是在java5.0后才引用的,泛型,可以让我们更安全的操作容器,而不用担心出现让人非常不快的ClassCastException异常,但是泛型没有多态的概念,Sun的那群大脑袋,就想到了一个解决办法,就是上界通配符<? extends T>,跟下界通配符(<? super T>),下面就介绍一下个人对它的理解吧,

 

首先,我们先定义几个类:

Leve2

class Food{}

Leve2

class Fruit{}
class Meat{}

Leve3

class Apple{}
class WaterMelon{}

 

继承关系图如下:

 

然后我们定义2个不使用通配符的方法:

    /**
	 * 不使用上界通配符
	 */
	public static void isUpMethod(List<Fruit> list){

	}


	/**
	 * 不使用下界通配符
	 */
	public static void isDownMethod(List<Fruit> list){

	}

 

接着,我们使用2个List,放函数里面存参数:

		List<Apple> apples = new ArrayList<>();

		apples.add(new Apple());
		apples.add(new Apple());
		apples.add(new Apple());

		//两个方法编译会报错
		//isUpMethod(apples);
		//isDownMethod(apples);

		List<Fruit> fruits = new ArrayList<>();

		fruits.add(new Fruit());
		fruits.add(new Fruit());
		fruits.add(new Fruit());

		//编译通过
		isUpMethod(fruits);
		isDownMethod(fruits);

有同学就会问了,List的泛型指定了Fruit类型,另外一个List泛型指定了Apple肯定编译不过去啊,但是,别忘了,Apple是Fruit的子类,我们理解中 Fruit fruit = new Apple();是可行的,因为java的多态;

但是,泛型是没有多态的,它可不认为Apple是Fruit的子类,如果这样的话,为代码重用代码很大的麻烦,因为泛型只是编译级别,在运行期间,泛型是会擦除的;

PS:指定泛型集合后,往内添加的元素可以是Fruit的子类,因为会自动向上转型,触发多态

如果想isUpdownMethod或者isDownMethod函数,接收其泛型类的子类或者父类,这时候,我们就可以使用上界通配符了<? extends Fruit>跟下界通配符<? super Fruit>

 

我们定义一个如下函数:

	/**
	 * 上界通配符
	 */
	public static void upMethod(List<? extends Fruit> list){
		//编译报错
		//使用通配符后,不能在往集合类中添加元素
		//list.add();


		//使用通配符后,是可以取出元素的
		//所有取出的元素,都是上界父类元素
		Fruit fruit = list.get(0);
	}


	/**
	 * 下界通配符
	 */
	public static void downMethod(List<? super Fruit> list){
		//下界通配符可以往容器内添加元素
		//但是有限制,必须是Fruit的子类或者本身,父类是添加不进去的
		list.add(new Apple());

		//取出元素的类型都为Object
		Object object = list.get(0);
	}

然后,我们试试使用往函数类传输LIST集合泛型指定是子类的集合:

        List<Apple> apples = new ArrayList<>();

		apples.add(new Apple());
		apples.add(new Apple());
		apples.add(new Apple());


		List<Fruit> fruits = new ArrayList<>();

		fruits.add(new Fruit());
		fruits.add(new Fruit());
		fruits.add(new Fruit());

		List<Food> foods = new ArrayList<>();

		foods.add(new Food());
		foods.add(new Food());
		foods.add(new Food());
		
		//编译通过
		upMethod(apples);
		upMethod(fruits);
		
		//编译通过
		downMethod(fruits);
		downMethod(foods);

 

 

上界通配符<? extends Fruit>

简介:

  •     上界通配符中的上界,指的是泛型内的类型,最高是Fruit类,最低不限,只要是继承了Fruit类,都可以通过编译,这也就是为什么叫 "上界",最高类型就是Fruit类          

描述:

  • 在upMethod函数中,使用上界通配符后,限定了条件,传参对象的泛型,必须是Fruit类或者其子类,才能通过编译,否则,编译就会失败,

  • 特性:
    • 在使用上界通配符后,我们不能在往集合内添加元素,那是因为,虽然指定了泛型的类型是Fruit类或者其子类,但是Fruit类可能并不止一个子类,可能除了Apple外还有Banana或者Watermelon类,如果你传递进来的是Apple集合,但是往里面添加Banana,这种情况下,往外取元素的时候很大的可能性会出现异常,因为取出的元素不是Apple而是Banana.所以,避免出现这种情况,使用上界通配符后,是不能再往集合内添加元素,
    • 可以往外取元素,所有取出的元素都是Fruit类,因为,编译器只知道是Fruit的子类,但是却不知道是具体哪个子类,所以取出的元素是最高层的类,也就是Fruit类

 

 

---------------------------------分割线----------------------------------------

 

 

下界通配符<? super Fruit>描述:

简介:

  •     下界通配符中的下界,指的是泛型内的类型,最低是Fruit类,最高到超类Object,只要是Fruit的父类,都可以通过编译,这也就是为什么叫 "下界",因为最低是Fruit类       

描述:

  • 在downMethod函数中,使用下界通配符后,限定了条件,传参对象的泛型,必须是Fruit类或者其父类,才能通过编译,否则,编译就会失败,

  • 特性:
    • 可以往集合内添加元素,但是限制条件是往内添加的元素,必须是Fruit的子类,因为虽然知道是Fruit的基类 但也不知道是往上数多少级的基类 只有Fruit以及它的子类 编译器才能断定能触发多态,
    • 可以往外取元素,但是取出来的元素都是Object,因为取出来的有可能是Food,比Fruit范围大,不能赋值给Fruit对象。只有Object可以,因为没有类比Object大。

 

 

---------------------------------分割线----------------------------------------

有人可能会问,为什么使用上界通配符后,不能往里存元素了,但是使用下界通配符能往里面存元素,原因如下:

  1. 上界通配符指定了上限,最高就是Fruit类,往里存元素,不是Fruit就是其子类啊,理论上是可以往内存的,那是因为使用上界通配符后,虽然有上限,但是没有下限啊,编译器,只知道是Fruit类或者是Fruit的子类,但是具体是哪个类型的子类,编译器也不知道,为了防止出现类型转换错误,所以,就禁止再往内添加元素(如果是我,我也会这么做,避免出现这样的情况)

  2. 下界通配符能往内存元素是因为下界通配符,规定了最小粒度的下限,是Fruit类.实际上是放松了对元素的类型控制,既然元素是Fruit类的父类,那往里存Fruit子类肯定可以的,因为Fruit的子类,也是其Fruit父类的子类,

  3. 上界通配符<? extends Fruit> 可以看成<?> 类型都不知道,肯定不让往里面添加元素,因为没有下限;也可以看成是一个可以放某种Fruit的集合,不是一个可以放任何Fruit的大杂烩集合
  4. 下界通配符<? super Fruit> 可以看成<Fruit>,确定了类型最低是Fruit,所以可以往内添加元素,但是必须是Fruit或者其子类​​​​​​​;也可以看成是一个可以放任何Fruit的集合

 

---------------------------------分割线----------------------------------------

 

总结:

  •         上界通配符<? extends T> 指的是,引用内的泛型范围,最高是T类,最低不限
    • 可以取元素
    • 不能添加元素
  •         下界通配符<? super T> 指的是,引用内的泛型范围,最低是T类,最高是超类Object
    • 可以取元素,但是取出的元素是Object
    • 可以添加元素,添加的元素,必须是T类或者其子类

 

到这,文章就结束了!

以上,均为本人理解,如果理解错误,欢迎指正

欢迎转载,请注明出处跟作者,谢谢!

 

© 著作权归作者所有

贺小五

贺小五

粉丝 73
博文 47
码字总数 48425
作品 0
海淀
程序员
私信 提问
加载中

评论(6)

贺小五
贺小五 博主

引用来自“Aldens”的评论

请问你在哪里上班?

北京啊
Aldens
Aldens
请问你在哪里上班?
贺小五
贺小五 博主

引用来自“donger11”的评论

有没有可能同时使用上界与下届,实现泛型区间?

引用来自“贺小五”的评论

不好意思,过年期间没看博客,这么晚才回复你,泛型区间这名称我没听过,不过你的意思是:同时使用上下界,直接泛型接收的范围是么?

引用来自“donger11”的评论

是的,之前在研究,貌似无法实现的
这个是无法实现的,因为编译器不能知道你这区间范围内有多大的范围
我是一只鱼_

引用来自“donger11”的评论

有没有可能同时使用上界与下届,实现泛型区间?

引用来自“贺小五”的评论

不好意思,过年期间没看博客,这么晚才回复你,泛型区间这名称我没听过,不过你的意思是:同时使用上下界,直接泛型接收的范围是么?
是的,之前在研究,貌似无法实现的
贺小五
贺小五 博主

引用来自“donger11”的评论

有没有可能同时使用上界与下届,实现泛型区间?
不好意思,过年期间没看博客,这么晚才回复你,泛型区间这名称我没听过,不过你的意思是:同时使用上下界,直接泛型接收的范围是么?
我是一只鱼_
有没有可能同时使用上界与下届,实现泛型区间?
Kotlin 范型之协变、逆变

一. 类(Class) 与类型(Type) Kotlin 中类和类型是不一样的概念。 下图充分展示了它们的区别。 二. 型变 型变是指转换后的继承关系。 Kotlin 的型变分为逆变、协变和不变。 2.1 协变 如果 A ...

fengzhizi715
06/24
0
0
困扰多年的Java泛型 extends T> super T>,终于搞清楚了!

一、为什么要用通配符和边界? 使用泛型的过程中,经常出现一种很别扭的情况。 比如我们有Fruit类,和它的派生类Apple 然后有一个最简单的容器:Plate类 盘子里可以放一个泛型的”东西” 我们...

编程SHA
05/30
498
0
利用有限制通配符提升API灵活性(28)

1、参数化类型是不可变的 List<String> 不是List<Object>的子类,但是二者是有联系的 利用有限制的通配符类型处理类似情况 List<? extends Object>(生产者) Collection<? super E>(消费者......

职业搬砖20年
2018/06/19
31
0
Java泛型_上界extends_下界super

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

秋风醉了
2015/11/07
674
1
10 道关于 Java 泛型的面试题

1.Java中的泛型是什么 ? 使用泛型的好处是什么? 这是在各种Java泛型面试中,一开场你就会被问到的问题中的一个,主要集中在初级和中级面试中。那些拥有Java1.4或更早版本的开发背景的人都知道...

蚂蚁-Declan
2018/10/24
193
0

没有更多内容

加载失败,请刷新页面

加载更多

003-ES集群

ES 集群 详情: https://my.oschina.net/u/3635512/blog/3140294 将实验机器/etc/elasticsearch/elasticsearch.yml 中配置文件改为 cluster.name: myes   #ES集群名称node.name:......

伟大源于勇敢的开始
32分钟前
8
0
法国电力项目二期正式验收

2019年12月10日, 法国电力项目二期正式验收 并就未来的合作技术方向进行了探讨: 去中心化数据存储/搜索引擎 可信计算/零知识证明 能源虚拟机改造 出席的人有: 法国电力总部 CIO&CTO Step...

怎当她临去时秋波那一转
48分钟前
5
0
谷歌助手

参照: https://www.mxblog.com.cn/mac%E7%89%88chrome%E6%B5%8F%E8%A7%88%E5%99%A8%E5%AE%89%E8%A3%85%E8%B0%B7%E6%AD%8C%E8%AE%BF%E9%97%AE%E5%8A%A9%E6%89%8B.html......

T型人才追梦者
57分钟前
6
0
索引延迟关联

前言 今天在看代码的时候学习到了一种索引的优化,就先在此记录下来。 具体 举个例子,原sql如下: SELECT * FROM TABLE WHERE INDEX = '' LIMIT 10000, 10; 现象 就算INDEX用了查询索引,...

无敌小杰杰
今天
6
0
tomcat_jdk安装,安装zrlog,nginx代理tomcat,第二个java应用

tomcat_jdk安装 要跑tomcat 首先要安装 jdk jdk 有两个版本 一个是 open jdk,一个是 oracle jdk open jdk 是 oracle jdk 的开源版本 两个版本都可以使用 这次实验先使用 open jdk 来做 如果...

doomcat
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部