泛型(Generic) <? extends T>,<? super T>
通配符边界引入背景
使用泛型的过程中,经常出现一种很别扭的情况。我们有 Fruit 类,和它的派生类 Apple 类。
class Fruit {}
class Apple extends Fruit {}
然后有一个最简单的容器:Plate 类。盘子里可以放一个泛型的 “东西”.
class Plate<T> {private T item;public Plate(T t) {item = t;}public void set(T t) {item = t;}public T get() {return item;}}
| 代码 | 我们想要表达的意思 | 实际效果 |
|---|---|---|
Plate<Apple> p2 = new Plate<Apple> (new Apple()); | 定义一个"苹果盘子" 装 苹果 | √ |
Plate<Fruit> p = new Plate<Apple> (new Apple()); | 定义一个"水果盘子",逻辑上水果盘子当然可以装苹果。 | error: incompatible types: Plate<Apple> cannot be converted to Plate<Fruit> |
实际上,编译器脑袋里认定的逻辑是这样的:
| 认可关系 | 不认可关系 |
|---|---|
苹果 IS-A 水果 | 装苹果的盘子 NOT-IS-A 装水果的盘子 |
就算容器里装的东西之间有继承关系,但容器之间是没有继承关系的。所以我们不可以把Plate<Apple>的引用传递给Plate<Fruit>。
为了解决这种情况,Sun的大脑袋们就想出了<? extends T>和<? super T>的办法,来让”水果盘子“和”苹果盘子“之间发生关系。
<? extends T> :上界通配符(Upper Bounds Wildcards)☞包括T在内的任何T的子类
意义
Plate<Apple> | Plate<?extends Fruit> |
|---|---|
一个能放苹果的盘子 | 一个能放任意水果的盘子 |
Plate<?extends Fruit> p = new Plate<Apple>(new Apple());可以用“ 苹果盘子”给“水果盘子”赋值了 | Plate<?extends Fruit>是Plate<Fruit>以及Plate<Apple>的基类 |
练习
| level1 | level2 | level3 | level4 |
|---|---|---|---|
class Food{} | class Fruit extends Food{} | class Apple extends Fruit{} | class RedApple extends Apple{} |
class GreenApple extends Apple{} | |||
class Banana extends Fruit{} | |||
class Meat extends Food{} | class Pork extends Meat{} | ||
class Beef extends Meat{} |
Plate<? extends Fruit> 覆盖区域
| level2 | level3 | level4 |
|---|---|---|
class Fruit extends Food{} | class Apple extends Fruit{} | class RedApple extends Apple{} |
class GreenApple extends Apple{} | ||
class Banana extends Fruit{} |
<?superT>:下界通配符(Lower Bounds Wildcards)☞包括T在内的任何T的父类
意义
Plate<Fruit> | Plate<?super Fruit> |
|---|---|
一个能放水果以及一切水果基类的盘子 | |
Plate<?super Fruit>是Plate<Fruit>的基类,但不是Plate<Apple>的基类 |
练习
Plate<?super Fruit>覆盖范围
| level1 | level2 |
|---|---|
class Food{} | class Fruit extends Food{} |
上下界通配符的副作用
边界让Java不同泛型之间的转换更容易了。这样的转换也有一定的副作用。那就是容器的部分功能失效。
还是以刚才的 Plate 为例。我们可以对盘子做两件事,往盘子里set()新东西,以及从盘子里get()东西。
- 上界
<? extends T>不能往里存,只能往外取
Plate<? extends Fruit> p=new Plate<Apple>(new Apple()); //不能存入任何元素
p.set(new Fruit()); //Error
p.set(new Apple()); //ErrorFruit newFruit1=p.get(); //读取出来的东西只能存放在Fruit或它的基类里
Object newFruit2=p.get();Apple newFruit3=p.get(); //Error
原因:
编译器只知道容器内是Fruit或者它的派生类,但具体是什么类型不知道。可能是 Fruit 可能是 Apple 也可能是 Banana,RedApple,GreenApple
编译器在看到后面用 Plate 赋值以后,盘子里没有被标上有 “苹果”。而是标上一个占位符:CAP#1,来表示捕获一个 Fruit 或 Fruit的子类,具体是什么类不知道,代号 CAP#1。然后无论是想往里插入 Apple 或者 Meat 或者 Fruit ,译器都不知道能不能和这个 CAP#1 匹配,所以就都不允许。
- 下界
<? super Fruit>不能往外取,只能往里存
Plate<? super Fruit> p=new Plate<Fruit>(new Fruit());//存入元素正常
p.set(new Fruit());
p.set(new Apple());Object newFruit2=p.get(); //读取出来的东西只能存放在Object类里Apple newFruit3=p.get(); //Error
Fruit newFruit1=p.get(); //Error
原因:
定义的元素是Fruit的基类,那往里存 Fruit及其父类 都可以。但往外读取元素就费劲了,只有 所有类的基类 Object对象 才能装下。但这样的话,元素的类型信息就全部丢失。
相关文章:
泛型(Generic) <? extends T>,<? super T>
通配符边界引入背景 使用泛型的过程中,经常出现一种很别扭的情况。我们有 Fruit 类,和它的派生类 Apple 类。 class Fruit {}class Apple extends Fruit {}然后有一个最简单的容器:Plate 类。盘子里可以放一个泛型的 “东西”. class Plat…...
数云融合|数字化转型中的利器:揭秘云技术的重要角色
数字化转型不仅是一个流行语,而是一项真正能够改变你的业务流程并提高客户参与度的重要战略。要实现数字化转型,必须重新构建业务流程,同时利用AI、物联网、AR、ML、大数据分析等先进技术不断提升客户参与度。这就需要利用云技术提供的强大计…...
Linux篇2
Linux 0. 终端提示信息1. 文件目录结构1.1 文件目录 2. 文本编辑器VI/VIM2.1 VIM编辑器2.1 一般模式2.2 编辑模式2.3 命令模式 3. 网络配置3.1 VMware提供的三种网络连接模式3.2 静态配置网络IP地址3.3 配置主机名3.3.1 修改主机名3.3.2 配置主机名-IP地址映射关系:…...
《微服务实战》 第九章 Gitlab使用
前言 微服务项目,常常需要多人协作完成工作,本章教程是介绍Gitlab使用,使多人协作告别低端的手动拷贝,也告别传统的SVN。 1、下载安装git https://git-scm.com/download/win 1.1、安装好以后,cmd中输入git 2、生成ssh-key ssh-keygen -t rsa -C “zhangsan@163.com”…...
KMP匹配算法
目录 一、暴力匹配法动画演示代码实现 二、KMP算法的概念三、KMP算法的应用题目代码实现 一、暴力匹配法 动画演示 时间复杂度为: O ( m ∗ n ) O(m * n) O(m∗n) 代码实现 #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;int…...
ClickHouse笔记: Ubuntu/Centos下的安装, 配置和用户管理
ClickHouse ClickHouse 属于 OLAP 数据库 OLTP 与 OLAP OLTP (On-Line Transaction Processing 联机事务处理), 注重事务处理, 数据记录的性能和安全性OLAP (On-Line Analytical Processing 联机分析处理), 注重数据分析, 重点在查询的性能 一般使用 OLTP 数据库做业务数据…...
网络编程——UDP编程
UDP编程 UDP编程步骤通信流程serverclient 函数接口socketbindrecvfromsendto 举例UDP客户端UDP服务器 UDP编程步骤 在C语言中进行UDP编程的一般步骤如下: (1)包含头文件: 在代码中包含必要的头文件,以便使用UDP编程所…...
linux内核篇-进程及其调度
介绍一个程序从源文件到进程执行的过程 1、编译链接(源文件到二进制文件) Linux 下面二进制的程序也要有严格的格式,称为ELF(Executeable and Linkable Format,可执行与可链接格式) ,这个格式可…...
C#开发的OpenRA游戏之基地工程车执行部署命令
C#开发的OpenRA游戏之基地工程车执行部署命令 前面已经分析接收到网络命令后,可以拿到多个命令对象, 通过命令对象进行遍历,最终会在比较部署命令的类里相同,从而执行部署命令。 可见,网络游戏里的对象操作,都是通过网络发送给服务器,再从服务器返回消息来执行对象的动…...
米哈游的春招实习面经,问的很基础
米哈游的春招实习面经,主要考察了java操作系统mysql网络,这四个方面。 面试流程,共1小时,1min自我介绍,20min写题,剩下问题基础知识。 Java String,StringBuilder, StringBuffer区…...
pro如何添加定时任务
Pro v2.4版本开始后台可以开关控制定时任务,那如何添加新的定时任务呢? 第一步:设置定时任务名称及标识; 文件app\controller\admin\v1\system\SystemTimer中task_name()方法 /**定时任务名称及标识 * return mixed */ public fu…...
bgp路由策略
* - valid 有效的, > - best 最佳的 上图中,有*和>,是有效最佳的。而没有*和没有>,是无效的,下一跳不可达 1--64511是公有AS 64512-65534为私有AS //属于哪个大的联盟 AS200 //连着一个子类AS 65002 //和子…...
chatGPT4.0编写性能测试报告
性能测试报告 测试概述 本次性能测试的目的是评估系统在高负载条件下的性能表现,以确保系统能够满足预期的性能需求。测试过程中,我们关注以下性能指标:响应时间、吞吐量、资源利用率(CPU、内存、磁盘、网络)以及错误…...
jpa多线程事务
百度都百度不到jpa多线程的事务回滚,废话少说,就是干, 实现思路(可看可不看,本人也不喜欢罗里吧嗦的,想直接看干货就跳过这里,直接执行代码): jpa本身是不支持多线程事务…...
加密解密软件VMProtect教程(四):准备项目之SDK功能
VMProtect 是保护应用程序代码免遭分析和破解的可靠工具,但只有在正确构建应用程序内保护机制并且没有可能破坏整个保护的典型错误的情况下才能最有效地使用。 SDK 功能可以集成到受保护应用程序的源代码中,以设置受保护区域的边界,以检测调…...
夏令营教育小程序开发功能和优势有哪些?
随着人们生活水平的提高,对于孩子的教育问题也是越来越重视,无论是教育方式还是教育内容上都追求新颖、多样化。在暑假期间,很多家长也希望孩子能够在这个长假期之间参加一些活动,培养孩子兴趣的同时也丰富假期内容,让…...
Cocos CreatorXR 1.2.0 今日发布,正式支持 WebXR ,并开启 MR 之路
去年九月,Cocos CreatorXR v1.0.1 版本支持了 VR 内容创作,成为率先支持 XR 的国产引擎,今年三月,Cocos CreatorXR v1.1.0 版本实现了对 AR 内容开发的支持。在完成基本功能的建设后,更多开发者开始尝试使用 Cocos Cre…...
Linux 使用笔记(本人出品,必属精品)
文章目录 Part.I IntroductionChap.I 快应用Chap.II 课程所学 Part.II 基础知识Chap.X 杂记 Part.I Introduction Linux 是笔者在大四上学期学的,当时授课的刘老师现在还能偶尔见到。但是平时一般用 Windows,有机会接触 Linux 一般是偶尔在服务器上跑跑程…...
【2023 · CANN训练营第一季】初识新一代开发者套件 Atlas 200I DK A2 第二章——安装Atlas 200I DK A2跑通第一个案例
准备相关软件 包括一台PC机(空间大于10g),读卡器,32gsd卡,一根网线。 具体步骤: 开始烧录开发板镜像:将sd卡插入读卡器,将读卡器插入PC机的USB接口,根据相关链接在PC机下载制卡工具…...
concurrenthashmap
SizeCtl的用法 sizeCtl0或容量大小 (二个构造方法) sizeCtl>0(初始化或扩容后)扩容阈值 sizeCtl-1:正在初始化中 sizeCtl<-1:线程扩容中 知道为什么第一个线程扩容时2,后面的其他线程扩容…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门  思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...
