【一文搞懂泛型】
3.3泛型
3.3.1泛型出现的背景
泛型出现的背景有两点:
- 第一点是在集合容器中,如果没有指定对应类型的话,那么底层的元素就是object,要对容器中的元素进行存取的时候,取出来的同时需要进行类型转换,如果有的类型不支持强制类型转换,这个时候就会报错,因此泛型的出现能够在一开始的时候就指定相应的类型,这就不会造成出错
- 第二点是为了实现代码的复用,比如有一个做加法的函数,加法既可以做int数据的加法,也可以做long数据的加法,但是如果没有泛型,固定写死的话,那就需要去根据不同的数据类型去创建对应的方法,有了泛型之后就可以在调用方法时,直接指定对应的类型就可以
3.3.2泛型的基本使用
- 泛型类
/*** 泛型类* @param <T>*/
class Obj<T>{T var;public T getObj(){return this.var;}
}
/*** 多元泛型类* @param <T,E>*/
class MutliObj<T,E>{T var1;E var2;public T getVar1(){return this.var1;}public T getvar2(){return this.var1;}}
- 泛型接口
/*** 泛型接口* @param <T>*/
interface Info<T>{/*** 在泛型接口中定义方法* @param info* @return*/public T getInfo(T info);
}/*** 实现泛型接口的类*/
class InfomationImpl implements Info<String>{String info;public void setInfo(String info){this.info = info;}@Overridepublic String getInfo(String info) {return info;}
}
- 泛型方法
/*** 定义泛型方法的类*/
class FxMethod {/*** 泛型方法* @param var1* @param var2* @param <T>* @param <E>* @return*/public <T,E> T method(T var1, E var2){if (var2!=null){System.out.println(var2);}return var1;}
}
- 泛型的上下限
- 泛型的上限,在做为参数的时候,使用?extends Father,表示,当前传入的参数只能是Father或者Father的子类才行
class Info<T extends Number>{ // 此处泛型只能是数字类型private T var ; // 定义泛型变量public void setVar(T var){this.var = var ;}public T getVar(){return this.var ;}public String toString(){ // 直接打印return this.var.toString() ;}
}
public class demo1{public static void main(String args[]){Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象}
}
- 泛型的下限,在声明泛型的时候,使用<? super Son>,表示,当前传入的参数只能是Son或者Son的父类才行
class Info<T>{private T var ; // 定义泛型变量public void setVar(T var){this.var = var ;}public T getVar(){return this.var ;}public String toString(){ // 直接打印return this.var.toString() ;}
}
public class GenericsDemo21{public static void main(String args[]){Info<String> i1 = new Info<String>() ; // 声明String的泛型对象Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象i1.setVar("hello") ;i2.setVar(new Object()) ;fun(i1) ;fun(i2) ;}public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型,String类的父类只有Object类System.out.print(temp + ", ") ;}
}
- 泛型数组,常用的集合如List,Set,Queue等,在定义时都会指定对应的类型,从而创建泛型数组
3.3.3泛型擦除
-
泛型其实是Java中的一个语法糖,为的就是解决上面所说的问题,而在编译成字节码的时候,会将<>里面的泛型都替换为确切的类,这个过程就是泛型擦除
-
泛型擦除包含了三种类型:
- 第一种是没有指定上下限的,在编译的时候就会将所有泛型都转换成Object类
- 第二种是指定了上限的,那么在编译的时候就会将所有泛型转换成上限这个类,比如,那在编译的时候就会转换成Number类
- 第三种是指定了下限的,在编译的时候会将所有泛型转换成指定下限的父类,比如<? super Number>,编译时会替换成Object
-
泛型擦除会有什么问题呢?
- 第一个问题
- 数据的继承性问题:在Java中,数据是具备继承性的,比如Integer 继承 Number,在数组中,如果定义Object[] objArr = new Object[3]; objArr[0]=“abc”;objArr[1]=1;这在编译的时候是没有问题的;
- 但是如果定义了ArrayList list = new ArrayList();这就会报错;因为在编译的时候,泛型会进行擦除,擦除之后的语句变成ArrayList list = new ArrayList();这样虽然看起来没什么问题,但是编译器对于左右两边的类型就无法判断是不是兼容。
- 再细致点讲,比如如下代码
- 第一个问题
List<Object> list = new ArrayList<>();list.add(123);list.add("abc"); List<String> newList = new ArrayList<>();newList = list;
上面的代码中,list和newList的类型是不一样的,对其进行赋值(相当于上面的操作),如果能赋值成功,那么久会导致newList中的元素既有int类型,又有String类型,这样是会造成错乱的,所以编译器不允许这种形式的存在。
第二个问题:
- 同样是因为数据具备继承性,比如我创建一个方法 method(List list);我希望我传入的是List类型的时候,这个方法也能调用,其实这个过程就转换成上面的第一问题了,我想传入子类参数,实际上就是赋值操作,让List list = new List,这显然是不可以的
- 这时候想到了,由于一个是Object类型的list,一个是String类型的list,那么我可不可以对方法进行重载呢,只要将参数设置成不同类型即可,就像下面的代码所示这样
public class Cmower {public static void method(Arraylist<Object> list) {System.out.println("Arraylist<Object> list");}public static void method(Arraylist<String> list) {System.out.println("Arraylist<String> list");}}
-
看似这样定义方法能解决上面的问题,但是实际上解决不了,同样是在编译的时候会进行泛型擦除,上面两个形参在编译时,他们的形参都会转成Arraylist list,这其实就变成了同一种方法,所以这种方式并不能解决上面的问题
-
泛型擦除可以怎么验证呢?
获得两个泛型的Class对象,让他们进行==操作,得到的结果是true
//泛型擦除ArrayList<String> arrlist1 = new ArrayList<>();ArrayList<Integer> arrlist2 = new ArrayList<>();System.out.println(arrlist1.getClass()==arrlist2.getClass());
3.3.4泛型通配符
-
在上面的泛型擦除问题中,讲到的两个问题,都导致了我们在使用泛型的时候,没办法用到数据的继承性,所以这个时候就出现了泛型通配符,为的就是解决上面的问题
-
泛型通配符的使用:
- <? extends Father>,表示这时候可以赋值Father及他的子类,如下面的代码
ArrayList<? extends Number> list = new ArrayList<Integer>();
我们来分析一下他为什么能解决上面的泛型擦除的问题,因为指定了当前ArrayList的上限为Number,所以在编译的时候,就知道无论如何,list中都是存放Number的子类对象的,就不用担心左右两边出现类型不确定的问题,如下面的代码
- <? super Son>,表示这时候可以赋值Son及他的父类,如下面的代码
ArrayList<? super Integer> list = new ArrayList<Number>();
原因其实和上面extends的一样
- <?>,只有通配符的话就表示没有限定类型
- <? extends Father>,表示这时候可以赋值Father及他的子类,如下面的代码
-
泛型通配符的使用场景:
-
上面的做法虽然解决了泛型擦除的问题,但是在实际使用中要注意使用的场景,这里有两条原则,就是用了<? extends Father>的集合不能调用add()方法;用了<? super Son>的集合不能调用get()方法,具体原因如下
- <? extends Father>的集合不能调用add()方法:
如果现在有一个集合ArrayList<? extends Number> list = new ArrayList<>(),同时允许去调用add()方法,那么既可以往里面加入int,也可以加入float,这样再去做赋值操作的话,比如list = new ArrayList();就会出现问题,因为new ArrayList()限定了类型只能为Integer,但是list里面确可能包含不止Integer一种类型的元素。把这个过程变成下面的代码
ArrayList<? extends Number> list = new ArrayList<>(); list.add(123); list.add(2.3); ArrayList<Integer> newList = new ArrayList<>(); //newList限定了类型,但是list中的元素包含不止Integer的类型 newList = list;
而<? super Son>的集合确可以调用add()方法,原因是,无论后面赋值的是什么类型的集合,都必须是Son或者Son的父类,因此就不会导致加入的元素和定义的类型不同的问题,比如下面的代码
ArrayList<? super Integer> list = new ArrayList<>(); list.add(123); ArrayList<Number> newList = new ArrayList<>(); newList.add(3.14); list = newList;- <? super Son>无法调用get()方法:
因为如果可以调用get()方法的话,这个list里面不仅包括Son,还可能包括Son的父类元素,比如下面的代码
ArrayList<? super Integer> list = new ArrayList<>(); list.add(123); ArrayList<Number> newList = new ArrayList<>(); newList.add(3.14); list = newList;
由于list可以被newList赋值,所以list里面并不一定只存放了Integer,还可能是Number,所以这是后去get(),就不确定是什么类型了。
而<?extends Father>是可以调用get()方法的,原因就在于,赋值的时候,必须是Father的子类,所以无论传入的是Father还是Father的子类,其实都是Father类,所以就不担心get的时候会搞不清是什么类型,如下面的代码
ArrayList<Integer> newList2 = new ArrayList<>(); newList2.add(123); ArrayList<Double> newList3 = new ArrayList<>(); newList3.add(2.3); list2=newList2; list2.get(0); list2 = newList3; list2.get(0); - <? extends Father>的集合不能调用add()方法:
-
相关文章:
【一文搞懂泛型】
3.3泛型 3.3.1泛型出现的背景 泛型出现的背景有两点: 第一点是在集合容器中,如果没有指定对应类型的话,那么底层的元素就是object,要对容器中的元素进行存取的时候,取出来的同时需要进行类型转换,如果有…...
概念解析 | 利用MIMO雷达技术实现高性能目标检测的关键技术解析
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:MIMO雷达目标检测技术 参考资料:何子述, 程子扬, 李军, 等. 集中式 MIMO 雷达研究综述[J]. 雷达学报, 2022, 11(5): 805-829. 利用MIMO雷达技术实现高性能目标检测的关键技术解…...
Grafana制作图表-自定义Flink监控图表
简要 有时候我们在官网的Grafana下载的图表是这样的,如下图 #算子的处理时间,就是处理数据的延迟数据抓取,这个的说明看下下面的文章 metrics.latency.interval: 60 metrics.reporter.promgateway.class: org.apache.flink.metrics.prometh…...
【TypeScript】初识TypeScript和变量类型介绍
TypeScript 1,TypeScript是什么?2,类型的缺失带来的影响3,Ts搭建环境-本博主有专门的文章专说明这个4,使用tsc对ts文件进行编译5,TS运行初体验简化Ts运行步骤解决方案1解决方案2(常见) 开始学习…...
阿里云瑶池 PolarDB 开源官网焕新升级上线
导读近日,阿里云开源云原生数据库 PolarDB 官方网站全新升级上线。作为 PolarDB 开源项目与开发者、生态伙伴、用户沟通的平台,将以开放、共享、促进交流为宗旨,打造开放多元的环境,以实现共享共赢的目标。 立即体验全新官网&…...
泡水书为什么不能再出售
近日,京津冀持续强降雨,多家出版机构位于涿州等地的图书库房受到影响。 中图网11日发文称,其位于涿州的仓储中心被洪水淹了,一库房有400多万册的书籍。 网友纷纷在文章下暖心留言:注意人身安全,泡水的书也…...
Mac 执行 .sh命令报错 command not found
使用终端执行.sh命令,可输入: ./FileName.sh如果提示 Permission denied 权限不足,可增加sudo,命令如下: sudo ./FileName.sh如果提示 command not found 可以这样: chmod ux *.sh sudo ./FileName.sh...
postgresql 使用之 存储架构 触摸真实数据的存储结构以及组织形式,存入数据库的数据原来在这里
存储架构 专栏内容: postgresql内核源码分析 手写数据库toadb 并发编程 个人主页:我的主页 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 概述 postgresql 数据库服务运行时,数据在磁…...
Node.Js安装与配置教程
目录 1.下载官网 2.选择安装路径 3.添加环境变量 4.验证是否安装成功 5.修改模块下载位置 (1)查看npm默认存放位置 6.在node.js安装目录下,创建两个文件夹 7.修改默认文件夹 8.测试默认位置是否更改成功 9.安装报错解决办法 10.路径未更改成功解决办法 …...
Element-Plus DatePicker获取时间戳
文章目录 0、先上答案1、渔?1-1 Element-Plus 官网1-2 溯源 Day.js 0、先上答案 <!-- 秒 --><el-date-pickerv-model"timeStamp"type"datetime"value-format"X"/><!-- 毫秒 --><el-date-pickerv-model"tim…...
【算法第十五天7.29】513.找树左下角的值 112. 路径总和 106.从中序与后序遍历序列构造二叉树
链接力扣513-找树左下角的值 思路 class Solution {public int findBottomLeftValue(TreeNode root) {Queue<TreeNode> queue new LinkedList<>();queue.offer(root);int res 0;while(!queue.isEmpty()){int size queue.size();for(int i 0; i < size; i)…...
Java thymeleaf bug排查记录
刚学Java 做项目时报了一个错误 一时间看的莫名其妙 EL1008E: Property or field createTime cannot be found on object of type java.util.HashMap - maybe not public or not valid? 随即向上排查至第一个报错,发现是thymeleaf渲染时报错。 Exception proces…...
互感和励磁电感(激磁电感)的关系
互感器,变压器,他们之间有着千丝万缕的联系,自感,互感,激磁电感,漏感、耦合系数、理想互感器、理想变压器,这些东西的概念理解和相互之间的关系式。都搞明白了吗?...
stdexcept和exception,两个头文件的区别?
stdexcept和exception是C标准库中的两个头文件,它们的区别如下: 1. 引用方式:stdexcept是exception的父类,引用时可以通过引用stdexcept来自动引用exception,也可以直接引用exception。 2. 异常处理:std…...
openCV图像的读写操作
文章目录 一、数组下标二、指针 void QuickDemo::pixel_visit_demo(cv::Mat &image) {int w image.cols;int h image.rows;int dim image.channels();for (int row 0; row < h; row){for (int col 0; col < w; col){if (dim 1)//灰度图像{int pv image.at<…...
Android平台GB28181设备接入端如何降低资源占用和性能消耗
背景 我们在做GB28181设备接入模块的时候,考虑到好多设备性能一般,我们一般的设计思路是,先注册设备到平台侧,平台侧发calalog过来,获取设备信息,然后,设备侧和国标平台侧维持心跳,…...
Android Studio安装AI编程助手Github Copilot
csdn原创谢绝转载 简介 文档链接 https://docs.github.com/en/copilot/getting-started-with-github-copilot 它是个很牛B的编程辅助工具,装它,快装它. 支持以下IDE: IntelliJ IDEA (Ultimate, Community, Educational)Android StudioAppC…...
windows部署springboot项目 jar项目 (带日志监听和开机自起脚本)
windows部署springboot项目 jar项目 (带日志监听) 1.把项目打包成jar包,本例演示打包后的jar文件名为demo.jar ———————————————— 2.需要装好java环境,配置好JAVA_HOME,CLASSPATH,PATH等…...
【数据结构和算法】排序算法
说明:以下排序如无特别说明,都是从小到大升序排序 1. 冒泡排序 核心思想:每个元素与其相邻元素比较,如果前者大于后者则交换,每次循环结束后会将最大值放到最后,像小水泡从底下冒到上面成大水泡一样&…...
Error: Cannot find module ‘@babel/core’处理
Error: Cannot find module babel/core’处理 问题产生的原因如何解决 在安装babel的时候,遇到个**Error: Cannot find module babel/core’**问题,查了很多资料才解决,希望能够帮助到各位兄弟。 问题产生的原因 babel-loader和babel-core版…...
2026年AI模型大战升级:Claude 4.6官网双版本发布,国内用户如何零门槛体验?
2026年2月,AI领域再起波澜。Anthropic在短短两周内连续推出Claude Opus 4.6与Sonnet 4.6双版本,以百万级上下文窗口与智能体协作能力,向OpenAI的GPT-5.4与谷歌的Gemini 3.1 Pro发起正面挑战。 对于国内AI爱好者、开发者与内容创作者而言&…...
新手也能懂:DCDC芯片外围那个神秘的‘自举电容’,到底怎么选才不会翻车?
新手也能懂:DCDC芯片外围那个神秘的‘自举电容’,到底怎么选才不会翻车? 第一次看到DCDC芯片数据手册里的"自举电容"时,我盯着那个连接在BTST和SW引脚之间的小元件发呆了十分钟——它看起来和普通电容没什么两样&#x…...
Youtu-Parsing模型C盘空间优化部署:清理与迁移实战指南
Youtu-Parsing模型C盘空间优化部署:清理与迁移实战指南 你是不是也遇到过这种情况?兴致勃勃地在Windows电脑上部署Youtu-Parsing这类大模型,准备大干一场,结果没跑几天,C盘就亮起了刺眼的红色警告。系统盘空间告急&am…...
OpenCore Legacy Patcher:让旧Mac重获新生的终极指南
OpenCore Legacy Patcher:让旧Mac重获新生的终极指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher OpenCore Legacy Patcher是一款革命性的开源…...
Graphormer效果展示:OGB-LSC PCQM4M榜单提交格式与验证流程
Graphormer效果展示:OGB-LSC PCQM4M榜单提交格式与验证流程 1. 模型概述 Graphormer是一种基于纯Transformer架构的图神经网络,专门为分子图(原子-键结构)的全局结构建模与属性预测而设计。该模型在OGB(Open Graph B…...
记录一次 反射引起的Metaspace OOM 的完整排查
一、问题背景线上某个 Spring Boot 服务偶发出现:java.lang.OutOfMemoryError: MetaspaceJVM 参数中已经限制:-XX:MetaspaceSize512m -XX:MaxMetaspaceSize512m但监控显示:Metaspace used ≈ 370MB Metaspace committed ≈ 508MB看起来仍…...
Gemini 3.1镜像实战:用三层思考架构与多模态引擎解决视频内容生产
谷歌2026年初发布的Gemini 3.1 Pro,凭借可配置的三层思考架构(低/中/高推理深度)和集成Veo视频引擎、Lyria 3音频引擎的多模态能力,为实际业务问题提供了全新的解决范式。国内开发者和内容创作者可通过聚合平台RskAi(w…...
零基础玩转像素心智:手把手教你用情绪解码器分析用户评论
零基础玩转像素心智:手把手教你用情绪解码器分析用户评论 1. 认识像素心智情绪解码器 1.1 什么是情绪解码器 像素心智情绪解码器(Pixel Mind Decoder)是一款基于M2LOrder核心引擎构建的AI情绪识别工具。它将复杂的自然语言处理技术封装在一个充满复古游戏风格的1…...
Cursor Pro免费激活指南:3步解锁AI编程工具的完整功能
Cursor Pro免费激活指南:3步解锁AI编程工具的完整功能 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached your tri…...
手把手教你学Simulink——基于Simulink的模型预测控制(MPC)PFC整流器快速动态响应
目录 手把手教你学Simulink ——基于Simulink的模型预测控制(MPC)PFC整流器快速动态响应 一、问题背景 二、系统建模与控制目标 1. 单相 Boost PFC 拓扑 2. 动态方程(αβ 静止坐标系) 3. 控制目标 三、有限控制集 MPC(FCS-MPC)设计 1. 预测模型(离散化) 2. 代…...
