Java泛型中<? extends E>和<? super E>的区别
这篇文章谈一谈Java泛型声明<? extends E>和<? super E>的作用和区别
<? extends E>
<? extends E> 是 Upper Bound(上限) 的通配符,用来限制元素的类型的上限,比如
- List<? extends Fruit> fruits;
表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类,因此对于下面的赋值是合理的
- fruits = new ArrayList<Fruit>();
- fruits = new ArrayList<Apple>();
如果集合中元素类型为Fruit的父类则会编译出错,比如
有了上面的基础,接着来看看 <? extends E>限定的集合的读写操作
1、写入
因为集合fruits中装的元素类型为Fruit或Fruit子类,直觉告诉我们,往fruits中添加一个Fruit类型对象或其子类对象是可行的
- fruits.add(new Fruit());//编译不通过
- fruits.add(new Apple());//编译不通过
结果是编译都不通过,为什么?因为<? extends Fruit>只是告诉编译器集合中元素的类型上限,但它具体是什么类型编译器是不知道的,fruits可以指向ArrayList<Fruit>,也可以指向ArrayList<Apple>、ArrayList<Banana>,也就是说它的类型是不确定的,既然是不确定的,为了类型安全,编译器只能阻止添加元素了。举个例子,当你添加一个Apple时,但fruits此时指向ArrayList<Banana>,显然类型就不兼容了。当然null除外,因为它可以表示任何类型。
2、读取
无论fruits指向什么,编译器都可以确定获取的元素是Fruit类型,所有读取集合中的元素是允许的
补充:<?>是<? extends Object>的简写
<? super E>
<? super E> 是 Lower Bound(下限) 的通配符 ,用来限制元素的类型下限,比如
表示集合中元素类型下限为Apple类型,即只能是Apple或Apple的父类,因此对于下面的赋值是合理的
- apples = new ArrayList<Fruit>();
- apples = new ArrayList<Object>();
如果元素类型为Apple的子类,则编译不同过
同样看看<? super E>限定的集合的读写操作
1、写入
因为apples中装的元素是Apple或Apple的某个父类,我们无法确定是哪个具体类型,但是可以确定的是Apple和Apple的子类是和这个“不确定的类”兼容的,因为它肯定是这个“不确定类型”的子类,也就是说我们可以往集合中添加Apple或者Apple子类的对象,所以对于下面的添加是允许的
- apples.add(new RedApple());
它无法添加Fruit的任何父类对象,举个例子,当你往apples中添加一个Fruit类型对象时,但此时apples指向ArrayList<Apple>,显然类型就不兼容了,Fruit不是Apple的子类
2、读取
编译器允许从apples中获取元素的,但是无法确定的获取的元素具体是什么类型,只能确定一定是Object类型的子类,因此我们想获得存储进去的对应类型的元素就只能进行强制类型转换了
问题来了,JDK1.5引入泛型的目的是为了避免强制类型转换的繁琐操作,那么使用泛型<? super E>干嘛呢?这里就得谈到泛型PECS法则了
PECS法则
PECS例子
* Copies all of the elements from one list into another. After the
* operation, the index of each copied element in the destination list
* will be identical to its index in the source list. The destination
* list must be at least as long as the source list. If it is longer, the
* remaining elements in the destination list are unaffected. <p>
*
* This method runs in linear time.
*
* @param dest The destination list.
* @param src The source list.
* @throws IndexOutOfBoundsException if the destination list is too small
* to contain the entire source List.
* @throws UnsupportedOperationException if the destination list's
* list-iterator does not support the <tt>set</tt> operation.
*/
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}
总结
- 频繁往外读取内容的,适合用上界Extends。
- 经常往里插入的,适合用下界Super。
Java泛型中<? extends E>和<? super E>的区别的更多相关文章
- 浅谈Java泛型之<? extends T>和<? super T>的区别
关于Java泛型,这里我不想总结它是什么,这个百度一下一大堆解释,各种java的书籍中也有明确的定义,只要稍微看一下就能很快清楚.从泛型的英文名字Generic type也能看出,Generic普通. ...
- Java泛型中extends和super的理解(转)
E – Element (在集合中使用,因为集合中存放的是元素) T – Type(Java 类) K – Key(键) V – Value(值) N – Number(数值类型) ? – 表示不确定 ...
- java泛型中extends 和 super的区别
一般对泛型中extends 和 super 的区别是这样介绍的: 关键字说明 ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类 < ...
- Java泛型中extends和super的区别?
<? extends T>和<? super T>是Java泛型中的"通配符(Wildcards)"和"边界(Bounds)"的概念. ...
- JAVA泛型知识--> <? extends T>和<? super T>
<? extends T> 和 <? super T> 是Java泛型中的“通配符(Wildcards)” 和 “边界(Bounds)”的概念 <? extends T& ...
- Java泛型中extends和super的理解
作者:zhang siege链接:https://www.zhihu.com/question/20400700/answer/91106397来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...
- JAVA 泛型 通配符? extends super限定,实例区分extends super限定的作用用法
java泛型中的关键字 ? 表示通配符类型 <? extends T> 既然是extends,就是表示泛型参数类型的上界,说明参数的类型应该是T或者T的子类. <? super T& ...
- Java泛型中<?> 和 <? extends Object>的异同分析
相信很多人和我一样,接触Java多年,却仍旧搞不清楚 Java 泛型中 <?>和 <? extends Object>的相似和不同.但是,这应该是一个比较高端大气上档次的Que ...
- 【转】聊一聊-JAVA 泛型中的通配符 T,E,K,V,?
原文:https://juejin.im/post/5d5789d26fb9a06ad0056bd9 前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型 ...
- Java泛型中的通配符T,E,K,V
Java泛型中的通配符T,E,K,V 1.泛型的好处 2.泛型中的通配符 2.1 T,E,K,V,? 2.2 ?无界通配符 2.3 上界通配符 < ? extends E> 2.4 下界通 ...
随机推荐
- 【Zabbix】Zabbix-agent自动化脚本
zabbix-agent自动化脚本 作用:批量部署zabbix-agent.用于上百台虚拟机都可以被Zabbix监控. 脚本名:inst-agent.sh #!/bin/bash echo " ...
- arcgis10.0的ArcGIS Services Directory显示401,需要身份验证,访问被拒绝,rest/services需要输入用户名和密码
大家好! 这个错误我也不想说什么,主要是应公司开发需求,从自己的arcgis10.2的版本改为arcgis10.0的版本,装完之后遇到一个错误,老是显示访问被拒绝,我也是找了很多的方式,没有在网上找到 ...
- (摘)使用 .NET Core 实现依赖关系注入
为什么使用依赖关系注入? 使用 .NET,通过 new 运算符(即,new MyService 或任何想要实例化的对象类型)调用构造函数即可轻松实现对象实例化.遗憾的是,此类调用会强制实施客户端(或应 ...
- 【AutoFac】依赖注入和控制反转的使用
在开始之前首先解释一下我认为的依赖注入和控制反转的意思.(新手理解,哪里说得不正确还请指正和见谅) 控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的 ...
- C# 在Word中添加表格的方法
表格是组织整理数据的一种重要手段,应在生活中的方方面面.在Word文档中将繁杂的文字表述内容表格化,能快速.直接地获取关键内容信息.那么,通过C#,我们也可以在Word文档中添加表格,这里将介绍两种不 ...
- Spring事务事件监控
前面我们讲到了Spring在进行事务逻辑织入的时候,无论是事务开始,提交或者回滚,都会触发相应的事务事件.本文首先会使用实例进行讲解Spring事务事件是如何使用的,然后会讲解这种使用方式的实现原理. ...
- Spring Boot 整合 docker
一.什么是docker ? 简介 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs ...
- 前端入门13-JavaScript进阶之原型
声明 本系列文章内容全部梳理自以下几个来源: <JavaScript权威指南> MDN web docs Github:smyhvae/web Github:goddyZhao/Trans ...
- Android 性能优化之减少UI过度绘制
什么是过度绘制(OverDraw) 在多层次重叠的UI结构里面,如果不可见的UI也在做绘制的操作,会导致某些像素区域被绘制了多次.这样就会浪费大量的CPU以及GPU资源.过度绘制最直观的影响就是会导致 ...
- web前端自动化测试/爬虫利器puppeteer介绍
web前端自动化测试/爬虫利器puppeteer介绍 Intro Chrome59(linux.macos). Chrome60(windows)之后,Chrome自带headless(无界面)模式很 ...