当前位置: 首页 > news >正文

【Java基础】泛型(二)-泛型的难点:通配符

本文将尝试将通配符和泛型中的继承,多态一并讲解

关于泛型中继承的注意事项

因为Integer、Double继承了Number,根据多态性,以下语句是合法的

Number n = new Integer(10); // OK, 父类引用变量可以指向子类对象
n = 2.9 // OK,n实际上会指向一个新的Double对象

但是注意,像ArrayList()、ArrayList()和ArrayList没有任何继承关系,考虑以下这个例子:

List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal,这一句不合法
ln.add(new Float(3.1415)); //这一句本来是合法,因为Float继承了Number。

对象ln是List类型,ln.add(new Float(3.1415))其实是合法的

但是如果你允许List类型的引用指向List,那么ln就是li的一个别名,这个List理论上就是个Integer列表,不能放Float类型对象了,这就产生了矛盾

而多态本身就是在运行时确定对象真正的类型,所以编译时发现不了ln.add(new Float(3.1415))其实已经不合法了

索性,编译时就不允许List ln = li

需要注意,以下这种泛型类是有继承关系的

//不替换
public class ArrayList<E> extends AbstractList<E>implements List<E> { //ArrayList后面必须添加<E>boolean add(E e);E get(int index);
}//替换
public class StringArrayList extends ArrayList<String> { boolean add(String e); //方法重写String get(int index);
}

这时,以下的继承关系都是正确的:

请添加图片描述

通配符类型

通配符介绍

上节说了半天,像ArrayList和ArrayList两者完全没有继承关系,其实就是为了引出通配符

因为这时泛型似乎不能利用多态的优点了,比如我就想在我的工具类里编写一个针对各种Number类型List的求和方法,我总不能对每种Number类型都写一个重载方法,这其实又违背了多态的理念

public Number sum(List<Number> list) {//求和
}

这种情况就可以用到通配符:?

例如这个求和方法就可以写成:

public Number sum(List<? extends Number> list) {//求和//get
}

这里的语义是:sum方法的入参可以是任何Number类型的List。(实际上,List<Integer>,List <Double>都属于List<? extends Number>的子类,因此多态性就可以体现出来了,这里的继承关系后面会进行总结

(需要注意的是,这时的sum方法其实已经不属于泛型方法了,“?”和类型参数“T”相比,不属于一个类型的形参,它其实和Integer、Number一样都属于实际类型,只不过它是“不确定类型”)

深入理解通配符

各种类型的通配符及继承关系

这一小节尝试将通配符和继承关系一并讲解:

其实,理解通配符的一个要点就是:通配符就是在泛型中实现多态的一种方式

通配符的种类有三种:

  1. 限定上界的通配符 List<? extends Number>
  2. 限定下界的通配符 List<? super Integer>
  3. 无界通配符 List<?>

同时,这些带通配符的类型,有以下的继承关系:

请添加图片描述

限定上界的通配符:上一节中我们已经编写了一个针对各种Number类型List的求和方法,利用的就是限定上界的通配符,因为List<Integer>,List<Double>等各种Number类型List都是List<? extends Number>的子类,所以我们将List<? extends Number>作为形参,很好地利用了多态性

限定下界的通配符:而限定下界的通配符,是希望未知类型“?”是某种特定类型的超类,比如说工具类中有一个方法是向list中添加Integer类型变量,那么这个list的类型可以是List, List, 或List,因为它们都可以存Integer类型,这时就可以用到限定下界的通配符

public static void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 10; i++) {list.add(i);}
}

从继承关系上看,这时的参数可以是List,当然也可以是List

无界通配符:其实List<?>就是List<? extends Object>,对比之前限定上界的例子,我们使用List<? extends Number>来声明求和方法,也是因为Number变量可以直接用+进行相加,但一般的Object变量没有相加的能力。换句话说,如果我们用List<?>来编写方法,我们仅会用到内部对象作为Object时的能力。
比如,编写一个方法让任何对象的list都能够逐一输出:

public static void printList(List<?> list) {for (Object elem: list)System.out.print(elem + " ");
}

另一种场景是,我们编写的方法用到了泛型类,但是调用的都是该泛型类中不依赖于类型参数的方法。
例如Collections中的shuffle方法,用于打乱list的顺序,其实它的逻辑就是将list中元素逐一和任意元素进行交换,因此需要遍历,调用list.size(), 而这个方法并不关心list<E>中的类型参数到底是啥

public static void shuffle(List<?> list, Random rnd)

各种类型通配符的使用指导

这里主要翻译官方教程的使用指导:

  1. 如果你使用的泛型类对象,是一个“in”变量,即为代码提供数据,就应该使用extends关键字
  2. 如果你使用的泛型类对象,是一个“Out”变量,即保存代码中的数据,就应该使用super关键字
  3. 如果仅会用到Object类定义的方法来访问“in”变量,就使用无界通配符
  4. 如果对象既是in或者out变量,就不要使用通配符
  5. 以上这些使用指导不适用于通配符出现在返回值的情况

Collections的copy方法其实就证实了前两点

public static <T> void copy(List<? super T> dest, List<? extends T> src) 

这里个人的理解是:限定输入类型的上界,输出类型的下界,这样数据从输入到输出会是向上转型,会是安全的。

另外,官方教程中也提到,一旦参数的类型是List<? extends …>,最好就让它只读,因为根据继承关系可能有以下问题

//自然数类
class NaturalNumber {private int i;public NaturalNumber(int i) { this.i = i; }// ...
}//偶数类
class EvenNumber extends NaturalNumber {public EvenNumber(int i) { super(i); }// ...
}List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35));  // 异常

相关文章:

【Java基础】泛型(二)-泛型的难点:通配符

本文将尝试将通配符和泛型中的继承&#xff0c;多态一并讲解 关于泛型中继承的注意事项 因为Integer、Double继承了Number&#xff0c;根据多态性&#xff0c;以下语句是合法的 Number n new Integer(10); // OK, 父类引用变量可以指向子类对象 n 2.9 // OK&#xff0c;n实…...

黑马】后台管理-两个括号的坑

记录一下这两天的坑没想到后台管理系统上线这两天都没有搞明白1.首先第一个坑是使用node.js的express中间件框架创建一个微型服务器&#xff0c;然后将vue脚手架生成的dist文件夹的文件放入里面了 &#xff0c;把项目加载到web服务器之后运行node .\app.js&#xff0c;页面显示…...

05:进阶篇 - 使用 CTKWidgets

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 CTKWidgets 包含了一组 Qt 部件,用于生物医学成像应用程序。当然,即使你的程序与医学无关,很多部件也是很有参考意义的。 在 CTK 源码中,有很多选项开关,可以控制你想要编译的内容(详见:04:进阶篇 …...

【YOLO V5】代码复现过程

接上篇&#xff0c;讲到如何从mask转成YOLOv5训练需要的txt数据集格式&#xff0c;这篇就在此基础上进行模型训练预测和部署转换吧&#xff01; 目录 1.环境准备 2.YOLO训练 2.1 数据集准备 2.2 data.yaml准备 2.3 yolov5.yaml准备 2.4 训练命令 3.YOLO预测 3.1OLOv5 P…...

汽车如何实现制动

汽车如何实现制动 汽车如何实现制动 难点答疑&#xff1a;汽车刹车时&#xff0c;四个车轮是如何制动的&#xff1f;制动机理是什么&#xff1f; 第一步&#xff1a;驾驶员踩下制动踏板&#xff0c;推动制动主缸 第二步&#xff1a;制动主缸将制动液的压力通过制动管道传递到四…...

cmake 引入第三方库(头文件目录、库目录、库文件)

程序的编写需要用到头文件&#xff0c;程序的编译需要lib文件&#xff0c;程序的运行需要dll文件&#xff0c;因此cmake引入第三方库其实就是将include目录、lib目录、bin目录引入工程。 目录 1、find_package&#xff08;批量引入库文件和头文件&#xff09; 2、include_dir…...

插件开发版|Authing 结合 APISIX 实现统一可配置 API 权限网关

当开发者在构建网站、移动设备或物联网应用程序时&#xff0c;API 网关作为微服务架构中不可或缺的控制组件&#xff0c;是流量的核心进出口。通过有效的权限管控&#xff0c;可以实现认证授权、监控分析等功能&#xff0c;提高 API 的安全性、可用性、拓展性以及优化 API 性能…...

deepinlinux v20安装rust和tauri并配置vscode开发工具过程

rust 很快进入linux内核开发&#xff0c;作为高效后台语言值得学习 tauri是代替electron的跨平台框架&#xff0c;不打包浏览器内核&#xff0c;所以打包出来体积小 安装rust 命令 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh 安装后看版本 rustc -V 看构…...

通俗易懂的机器学习——sklearn鸢尾花分类(KNN)

前言 KNN算法是机器学习中较为简单的入门算法&#xff0c;其主要思想是选取k个与待预测点相近的数据&#xff0c;观察他们的类别&#xff0c;本着离谁近就更像谁的思路对于待预测点进行预测&#xff0c;本文将针对使用sklearn进行KNN算法的使用进行详解 数据预处理 在正式开…...

操作系统引论

操作系统是管理硬件和软件的一种应用程序。操作系统是运行在计算机上最重要的一种软件&#xff0c;它管理计算机的资源和进程以及所有的硬件和软件。它为计算机硬件和软件提供了一种中间层&#xff0c;使应用软件和硬件进行分离&#xff0c;让我们无需关注硬件的实现&#xff0…...

优质 CS 读博 (PhD) 经验贴汇总

前言 如果你对这篇文章可感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 Advice for early-stage Ph.D. students 读博的核心是在研究上取得进展&#xff0c;只有在研究上取得一些进展&#xff…...

SpringCloud学习笔记 - @SentinelResource的fallbackblockHandler配置详解 - sentinel

1. sentinel服务负载均衡测试 sentinel默认开启了负载均衡的轮询模式&#xff0c;为了测试sentinel服务负载均衡的效果&#xff0c;需要先创建两个服务提供者和一个服务消费者。 1.1. 分别创建两个服务提供者-支付服务9003、9004 1. 添加pom依赖&#xff1a; 提供者只需要将…...

华为OD机试题 - 静态扫描最优成本(JavaScript)

最近更新的博客 2023新华为OD机试题 - 斗地主(JavaScript)2023新华为OD机试题 - 箱子之形摆放(JavaScript)2023新华为OD机试题 - 考古学家(JavaScript)2023新华为OD机试题 - 相同数字的积木游戏 1(JavaScript)2023新华为OD机试题 - 最多等和不相交连续子序列(JavaScri…...

mysql大数据量批量提交

DROP PROCEDURE IF EXISTS test.insert_bacth_commit_test1;CREATE PROCEDURE test.insert_bacth_commit_test1()begindeclare start_num int default 0; -- 初始设置起始行数declare end_num int default 5;-- 初始设施结束行数declare cnt_srouce int default 0; -- 定义源表…...

IP SAN组网配置

目录一、确认网络连接畅通二、服务器端ISCSI启动器配置1.以root身份登录2.验证是否已安装iSCSI启动器3.安装iSCSI启动器4.启动iSCSI服务5.给iSCSI启动器命名6.扫描目标器7.登录目标器8.将登录目标器行为设置为自启动三、主机多路径配置四、存储配置五、主机挂载背景&#xff1a…...

面试7分看能力,3分靠嘴皮,剩下90分就靠这份Java面试八股文

有句话说的好&#xff0c;面试中7分靠能力&#xff0c;3分靠嘴皮刚开始面试的时候&#xff0c;介绍项目一般都是凸显我们技能的重中之重&#xff0c;它对一次面试的成败可以说具有决定性作用&#xff0c;这就涉及到我们的表达能力了&#xff0c;有人说我其实水平都在线&#xf…...

api接口如何对接?

对于很多产品小白或求职者而言&#xff0c;API接口是一个产品和研发领域的专业术语&#xff0c;大家可能在文章或者PRD中都已经有接触过API接口的概念。 实际上&#xff0c;接口的应用已经非常广泛和成熟&#xff0c;这个概念主要活跃在公司内部的各系统之间的衔接和对接以及公…...

毕业2年不到选择跳槽,居然拿到25K的薪资,简直了···

本人本科就读于某普通院校&#xff0c;毕业后通过同学的原因加入软件测试这个行业&#xff0c;角色也从测试小白到了目前的资深工程师&#xff0c;从功能测试转变为测试开发&#xff0c;并顺利拿下了某二线城市互联网企业的Offer&#xff0c;年薪 30W 。 选择和努力哪个重要&am…...

Java反序列化漏洞——CommonsCollections3链分析

一、原理CC1链中我们是通过调用Runtime.getRuntime.exec()来执行系统命令&#xff0c;而另一个方向我们可以通过TemplatesImpl加载字节码的类&#xff0c;通过调⽤其newTransformer() 方法&#xff0c;即可执⾏这段字节码的类构造器&#xff0c;我们在类构造器中加入恶意代码&a…...

英文论文(sci)解读复现【NO.5】让RepVGG再次变得更强大:一种量化感知方法

此前出了目标检测算法改进专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读发表高水平学术期刊中的SCI论文&am…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...