疯狂Java讲义_08_泛型
文章目录
- 泛型的传参
- 若函数里的参数使用基类接受所有的派生类,怎么做?
- 类型通配符的上限
- 类型通配符的下限
泛型的传参
注意
若类 Base 是类 Derived 的基类(父类),那么数组类型 Base[] 是 Derived[] 的基类(父类)。但是集合类型 List<Base> 不是 List<Derived> 的基类(父类)。
若函数里的参数使用基类接受所有的派生类,怎么做?
例如:函数里的参数要接受所有的List类,包括 List<Integer>, List<String> 等。
public class Test01 {public static void main(String[] args) {ArrayList<String> strList = new ArrayList<String>();strList.add("good");strList.add("man");strList.add("helo");testGenericParameter(strList);}
// 形参类型 可以使用 List (会有警告),List<?> (推荐,没有警告), 不可以使用 List<Object>private static void testGenericParameter(List<?> list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}
}
例如:Shape 是基类,Circle、Rectangle 是派生类
只想要接受所有Shape派生类的入参
// ? extends Shape 表示 所有从Shape派生出的类
void testGenericParameter(List<? extends Shape> list) {}
? extends Shape表示 所有 Shape 的派生类? super Shape表示所有 Shape 的基类(父类)
类型通配符的上限
List<? extends Shape> 是受限制通配符的例子,此处的问号(? )代表一个未知的类型,就像前面看到的通配符一样。但是此处的这个未知类型一定是Shape的子类型(也可以是Shape本身),因此可以把Shape称为这个通配符的上限(upper bound)。
类似地,由于程序无法确定这个受限制的通配符的具体类型,所以不能把Shape对象或其子类的对象加入这个泛型集合中。例如,下面代码就是错误的

与使用普通通配符相似的是,shapes.add()的第二个参数类型是 ? extends Shape,它表示Shape未知的子类,程序无法确定这个类型是什么,所以无法将任何对象添加到这种集合中。
简而言之,这种指定通配符上限的集合,只能从集合中取元素(取出的元素总是上限的类型或其子类),不能向集合中添加元素(因为编译器没法确定集合元素实际是哪种子类型)。
对于更广泛的泛型类来说,指定通配符上限就是为了支持类型型变。比如Foo是Bar的子类,这样A<Foo> 就相当于A<? extends Bar> 的子类,可以将A<Foo> 赋值给A<? extends Bar> 类型的变量,这种型变方式被称为协变。
对于协变的泛型而言,它只能调用泛型类型作为返回值类型的方法(编译器会将该方法返回值当成通配符上限的类型);而不能调用泛型类型作为参数的方法。 口诀是:协变只出不进!
提示:没有指定通配符上限的泛型类,相当于通配符上限是Object 。例如 List<?> 表示 类型上限是Object
类型通配符的下限
除可以指定通配符的上限之外,Java也允许指定通配符的下限,通配符的下限用<? super 类型> 的方式来指定,通配符下限的作用与通配符上限的作用恰好相反。
指定通配符的下限就是为了支持类型型变。比如Foo是Bar的子类,当程序需要一个A<? super Foo> 变量时,程序可以将A<Bar> 、A<Object> 赋值给A<? super Foo> 类型的变量,这种型变方式被称为逆变。
对于逆变的泛型集合来说,编译器只知道集合元素是下限的父类型,但具体是哪种父类型则不确定。因此,这种逆变的泛型集合能向其中添加元素(因为实际赋值的集合元素总是逆变声明的父类),从集合中取元素时只能被当成Object类型处理(编译器无法确定取出的到底是哪个父类的对象)。
对于逆变的泛型而言,它只能调用泛型类型作为参数的方法;而不能调用泛型类型作为返回值类型的方法。 口诀是:逆变只进不出!
设自己实现一个工具方法:实现将src集合中的元素复制到dest集合的功能,因为dest集合可以保存src集合中的所有元素,所以dest集合元素的类型应该是src集合元素类型的父类。
对于上面的copy()方法,可以这样理解两个集合参数之间的依赖关系:不管src集合元素的类型是什么,只要dest集合元素的类型与前者相同或者是前者的父类即可,此时通配符的下限就有了用武之地。
下面程序采用通配符下限的方式来实现该copy()方法。
public class TestGenericType {public static void main(String[] args) {ArrayList<Number> list1 = new ArrayList<Number>();ArrayList<Integer> list2 = new ArrayList<Integer>();list2.add(1);list2.add(2);list2.add(3);Integer last = copy(list1, list2);//①System.out.println(list1);}// dest 集合里的元素的类型必须是 src 集合元素的类型 或 其父类public static <T> T copy(Collection<? super T> dest, Collection<T> src) {T last = null;for (T ele : src) {last = ele;//逆变的泛型集合添加元素是安全的dest.add(ele);}return last;}
}
使用这种语句,就可以保证程序的①处调用后推断出最后一个被复制的元素类型是Integer,而不是笼统的Number类型。
实际上,Java集合框架中的TreeSet< E> 有一个构造器也用到了这种设定通配符下限的语法,如下所示。
public TreeSet(Comparator<? super E> comparator) {//...}
正如前一章所介绍的,TreeSet会对集合中的元素按自然顺序或定制顺序进行排序。如果需要TreeSet对集合中的所有元素进行定制排序,则要求TreeSet对象有一个与之关联的Comparator对象。上面构造器中的参数comparator就是进行定制排序的Comparator对象。
Comparator接口也是一个带泛型声明的接口
public interface Comparator<T> {int compare(T o1, T o2);
}
通过这种带下限的通配符的语法,可以在创建TreeSet对象时灵活地选择合适的Comparator。
假定需要创建一个TreeSet<String> 集合,并传入一个可以比较String大小的Comparator,这个Comparator既可以是Comparator<String> ,也可以是Comparator<Object> 只要尖括号里传入的类型是String的父类型(或它本身)即可。
private static void test02() {// 既可以使用 new Comparator<Object> 因为 Object 是 String 的父类,也可以使用 Comparator<String> 作为构造器的参数TreeSet<String> set1 = new TreeSet<String>(new Comparator<Object>() {@Overridepublic int compare(Object o1, Object o2) {return o1.hashCode() > o2.hashCode() ? 1 :o1.hashCode() < o2.hashCode() ? -1 : 0;}});set1.add("hello");set1.add("wa");TreeSet<String> set2 = new TreeSet<String>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.length() > o2.length() ? -1 :o1.length() < o2.length() ? 1 : 0;}});set2.add("hello");set2.add("wa");System.out.println(set1);System.out.println(set2);}
通过使用这种通配符下限的方式来定义TreeSet构造器的参数,就可以将所有可用的Comparator作为参数传入,从而增加了程序的活性。当然,不仅TreeSet有这种用法,TreeMap也有类似的用法,具体的请查阅Java的API文档。
相关文章:
疯狂Java讲义_08_泛型
文章目录 泛型的传参若函数里的参数使用基类接受所有的派生类,怎么做? 类型通配符的上限类型通配符的下限 泛型的传参 注意 若类 Base 是类 Derived 的基类(父类),那么数组类型 Base[] 是 Derived[] 的基类࿰…...
HCIA、OSPF笔记
一、OSI参考模型 1、OSI的结构 应用层:把人类语言转化成编码,为各种应用程序提供网络服务。 表示层:定义一些数据的格式,(对数据进行加密、解密、编码、解码、压缩、解压缩,每一层都可以实现,…...
Python删除lru_cache缓存
在 Python 中,lru_cache 是一个装饰器,用于添加缓存功能以提高函数的性能。如果你想清除或者删除 lru_cache 中的缓存,有几种方法可以做到: 手动清除缓存: lru_cache 对象有一个方法叫做 cache_clear(),可以手动清除所有缓存。示例:@lru_cache(maxsize=128) def some_fun…...
Android面试必问题:大白文讲透Android View工作原理
目录 第一章 引言 第二章 Android View 基础概念 2.1 视图(View) 2.2 布局(Layout) 2.3 绘制(Drawing) 第三章 Android View 工作原理详解 3.1 测量过程剖析 3.2 布局流程探究 第四章 Android View 性能优化建议 4.1 视图层级优化 4.2 避免过度的视觉效果 4.…...
WinDbg配置远程调试
WinDbg配置远程调试 1、为什么需要远程调试 某些特殊的场合需要远程调试,如: ①调试特殊的程序,比如在调试全屏程序,内核。 ②需要别人帮助调试或者帮助别人调试。比如由于商业性质不能直接给你pdb和源代码。 ③还有一类就是…...
spl注入实战thinkphp
目录 一、环境的部署 二、本地创建数据库 三、填写数据库连接文件 四、编写控制器 五、访问分析 debug报错会显示物理路径 原因是config.php文件相关配置 六、注入分析 七、进入断点调试 八、通过mysql执行语句查看结果 九、总结: 一、环境的部署 二、本地…...
整理深度学习时最常用的Linux命令(自用)
清华大学镜像源: https://pypi.tuna.tsinghua.edu.cn/simple/tar文件解压 tar -xzvf xxx.tar.gztar xvf xxx.tarzip文件解压 unzip xxx.zip -d path/to/your/fold清理GPU异常内存占用 杀掉 1 号显卡的所有进程 fuser -v /dev/nvidia1 | xargs -t -n 1 kill -9杀掉…...
LVS——>linux 虚拟服务器知识汇总
一、概念: LVS(Linux Virtual Server),是Linux Virtual Server的简写,也就是Linux 虚拟服务器,是一个虚拟的服务器集群系统负载均衡解决方案,它将一个真实服务器集群虚拟成一台服务器来对外提供…...
AI赋能周界安防:智能视频分析技术构建无懈可击的安全防线
周界安全防范是保护机场、电站、油库、监狱、工业园区等关键设施免受非法入侵和破坏的重要措施。传统的周界安防手段主要依靠人员巡查和物理屏障,但这种方式不仅人力成本高,而且效率较低,难以满足日益复杂多变的安全需求。随着AI技术的引入&a…...
FastAPI+Vue3工程项目管理系统项目实战私教课 上课笔记20240808 课程和学习计划制定
学习目标 将Word和Excel做的东西放到数据库里面去工程类公司,甲方,劳务存到数据库存储的信息主要是人员的信息 基本信息: 人员信息,资料库,甲方的人出现在哪些项目上,考勤材料信息,进货记录&…...
Robot Operating System——发布相对湿度数据
大纲 应用场景定义字段解释 案例 sensor_msgs::msg::RelativeHumidity 是 ROS (Robot Operating System) 中的一个消息类型,用于表示相对湿度数据。 应用场景 环境监测 气象站:在气象站中,相对湿度传感器可以用于监测环境湿度,帮…...
一文搞懂后端面试之不停机数据迁移【中间件 | 数据库 | MySQL | 数据一致性】
数据迁移方面的工作: 重构老系统:使用新的表结构来存储数据单库拆分分库分表、分库分表扩容大表修改表结构定义 数据备份工具 MySQL上常用的两款数据备份工具:mysqldump和XtraBackup mysqldump:一个用于备份和恢复数据库的命令…...
【ESP01开发实例】- ISD1820录音控制
ISD1820录音控制 文章目录 ISD1820录音控制1、ISD1820模块介绍2、硬件准备及接线3、代码以实现录音技术已经取得了长足的进步,它已成为从语音助手到安全系统的各种应用不可或缺的一部分。如果您有兴趣构建自己的录音系统,将 ISD1820 模块与 ESP01 微控制器相结合可能是一个不…...
Linux驱动面试高频考点后面继续改整理
Linux驱动开发是将硬件设备与操作系统内核连接起来的重要环节,它涉及到设备模型、中断处理、文件操作等方面,是一项挑战性且充满乐趣的工作。今天给大家分享45道Linux驱动面试高频考点,直接上干货。 1、驱动程序分为几类? 内核驱动…...
【Python】nn.ConvTranspose1、2、3d()函数详解和示例
前言 在深度学习中,特别是在处理图像、音频和三维数据时,转置卷积(Transposed Convolution)或称为反卷积(Deconvolution)是一种非常重要的操作。PyTorch提供了nn.ConvTranspose1d、nn.ConvTranspose2d和nn…...
vtkConnectivityFilter提取连通区域中的问题
直接使用vtkConnectivityFilter提取连通区域,渲染上没问题,但是打印出polydata中的点数,发现跟原始数据是一致的。 for (int i 0; i < numRegions; i){vtkSmartPointer<vtkConnectivityFilter> connectivityFilter vtkSmartPointe…...
购物系统小程序的设计
管理员账户功能包括:系统首页,个人中心,商品分类管理,商品信息管理,特价商品管理,用户管理,留言板管理,订单管理,系统管理 微信端账号功能包括:系统首页&…...
做报表用什么工具?不想再用Excel了!!!
一、什么是中国式报表? 不知道大家现在还是使用Excel来制作报表,然后跟领导汇报工作吗?虽然Excel功能很强大,但是用Excel做过中国式报表的小伙伴一定知道它的制作过程有多复杂。 中国式报表可以用一句话简单概括:格式…...
c++实现学生管理系统(附源码)
目录 一、基本功能: 二、包含的模块: 三、系统介绍 1. 学生管理系统的功能: 2. 具体的需求: 3. 支持的标准: 四、系统结构功能图: 五、系统设计 1. 退出系统: 2. 增加学生:…...
JS防抖是什么?干嘛用的?
你好同学,我是沐爸,欢迎点赞、收藏和关注!个人知乎 防抖在前端开发中可以说经常用到,有诸多使用场景。接下来我们一起看下防抖的定义、防抖函数的实现、应用场景、lodash防抖函数以及防抖在框架中的使用。Let’s go 一、什么是防…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
