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

【一文搞懂泛型】

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>的集合不能调用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);
      

相关文章:

【一文搞懂泛型】

3.3泛型 3.3.1泛型出现的背景 泛型出现的背景有两点&#xff1a; 第一点是在集合容器中&#xff0c;如果没有指定对应类型的话&#xff0c;那么底层的元素就是object&#xff0c;要对容器中的元素进行存取的时候&#xff0c;取出来的同时需要进行类型转换&#xff0c;如果有…...

概念解析 | 利用MIMO雷达技术实现高性能目标检测的关键技术解析

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:MIMO雷达目标检测技术 参考资料:何子述, 程子扬, 李军, 等. 集中式 MIMO 雷达研究综述[J]. 雷达学报, 2022, 11(5): 805-829. 利用MIMO雷达技术实现高性能目标检测的关键技术解…...

Grafana制作图表-自定义Flink监控图表

简要 有时候我们在官网的Grafana下载的图表是这样的&#xff0c;如下图 #算子的处理时间&#xff0c;就是处理数据的延迟数据抓取&#xff0c;这个的说明看下下面的文章 metrics.latency.interval: 60 metrics.reporter.promgateway.class: org.apache.flink.metrics.prometh…...

【TypeScript】初识TypeScript和变量类型介绍

TypeScript 1&#xff0c;TypeScript是什么?2&#xff0c;类型的缺失带来的影响3&#xff0c;Ts搭建环境-本博主有专门的文章专说明这个4&#xff0c;使用tsc对ts文件进行编译5&#xff0c;TS运行初体验简化Ts运行步骤解决方案1解决方案2&#xff08;常见&#xff09; 开始学习…...

阿里云瑶池 PolarDB 开源官网焕新升级上线

导读近日&#xff0c;阿里云开源云原生数据库 PolarDB 官方网站全新升级上线。作为 PolarDB 开源项目与开发者、生态伙伴、用户沟通的平台&#xff0c;将以开放、共享、促进交流为宗旨&#xff0c;打造开放多元的环境&#xff0c;以实现共享共赢的目标。 立即体验全新官网&…...

泡水书为什么不能再出售

近日&#xff0c;京津冀持续强降雨&#xff0c;多家出版机构位于涿州等地的图书库房受到影响。 中图网11日发文称&#xff0c;其位于涿州的仓储中心被洪水淹了&#xff0c;一库房有400多万册的书籍。 网友纷纷在文章下暖心留言&#xff1a;注意人身安全&#xff0c;泡水的书也…...

Mac 执行 .sh命令报错 command not found

使用终端执行.sh命令&#xff0c;可输入&#xff1a; ./FileName.sh如果提示 Permission denied 权限不足&#xff0c;可增加sudo&#xff0c;命令如下&#xff1a; sudo ./FileName.sh如果提示 command not found 可以这样: chmod ux *.sh sudo ./FileName.sh...

postgresql 使用之 存储架构 触摸真实数据的存储结构以及组织形式,存入数据库的数据原来在这里

存储架构 ​专栏内容&#xff1a; postgresql内核源码分析 手写数据库toadb 并发编程 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 概述 postgresql 数据库服务运行时&#xff0c;数据在磁…...

Node.Js安装与配置教程

目录 1.下载官网 2.选择安装路径 3.添加环境变量 4.验证是否安装成功 5.修改模块下载位置 (1)查看npm默认存放位置 6.在node.js安装目录下&#xff0c;创建两个文件夹 7.修改默认文件夹 8.测试默认位置是否更改成功 9.安装报错解决办法 10.路径未更改成功解决办法 …...

Element-Plus DatePicker获取时间戳

文章目录 0、先上答案1、渔&#xff1f;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? 随即向上排查至第一个报错&#xff0c;发现是thymeleaf渲染时报错。 Exception proces…...

互感和励磁电感(激磁电感)的关系

互感器&#xff0c;变压器&#xff0c;他们之间有着千丝万缕的联系&#xff0c;自感&#xff0c;互感&#xff0c;激磁电感&#xff0c;漏感、耦合系数、理想互感器、理想变压器&#xff0c;这些东西的概念理解和相互之间的关系式。都搞明白了吗&#xff1f;...

stdexcept和exception,两个头文件的区别?

stdexcept和exception是C标准库中的两个头文件&#xff0c;它们的区别如下&#xff1a; 1. 引用方式&#xff1a;stdexcept是exception的父类&#xff0c;引用时可以通过引用stdexcept来自动引用exception&#xff0c;也可以直接引用exception。 2. 异常处理&#xff1a;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设备接入模块的时候&#xff0c;考虑到好多设备性能一般&#xff0c;我们一般的设计思路是&#xff0c;先注册设备到平台侧&#xff0c;平台侧发calalog过来&#xff0c;获取设备信息&#xff0c;然后&#xff0c;设备侧和国标平台侧维持心跳&#xff0c;…...

Android Studio安装AI编程助手Github Copilot

csdn原创谢绝转载 简介 文档链接 https://docs.github.com/en/copilot/getting-started-with-github-copilot 它是个很牛B的编程辅助工具&#xff0c;装它&#xff0c;快装它&#xff0e; 支持以下IDE: IntelliJ IDEA (Ultimate, Community, Educational)Android StudioAppC…...

windows部署springboot项目 jar项目 (带日志监听和开机自起脚本)

windows部署springboot项目 jar项目 &#xff08;带日志监听&#xff09; 1.把项目打包成jar包&#xff0c;本例演示打包后的jar文件名为demo.jar ———————————————— 2.需要装好java环境&#xff0c;配置好JAVA_HOME&#xff0c;CLASSPATH&#xff0c;PATH等…...

【数据结构和算法】排序算法

说明&#xff1a;以下排序如无特别说明&#xff0c;都是从小到大升序排序 1. 冒泡排序 核心思想&#xff1a;每个元素与其相邻元素比较&#xff0c;如果前者大于后者则交换&#xff0c;每次循环结束后会将最大值放到最后&#xff0c;像小水泡从底下冒到上面成大水泡一样&…...

Error: Cannot find module ‘@babel/core’处理

Error: Cannot find module babel/core’处理 问题产生的原因如何解决 在安装babel的时候&#xff0c;遇到个**Error: Cannot find module babel/core’**问题&#xff0c;查了很多资料才解决&#xff0c;希望能够帮助到各位兄弟。 问题产生的原因 babel-loader和babel-core版…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

Mac flutter环境搭建

一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...

门静脉高压——表现

一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构&#xff1a;由肠系膜上静脉和脾静脉汇合构成&#xff0c;是肝脏血液供应的主要来源。淤血后果&#xff1a;门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血&#xff0c;引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架

文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理&#xff1a;检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目&#xff1a;RankRAG&#xff1a;Unifying Context Ranking…...

Qt的学习(二)

1. 创建Hello Word 两种方式&#xff0c;实现helloworld&#xff1a; 1.通过图形化的方式&#xff0c;在界面上创建出一个控件&#xff0c;显示helloworld 2.通过纯代码的方式&#xff0c;通过编写代码&#xff0c;在界面上创建控件&#xff0c; 显示hello world&#xff1b; …...

工厂方法模式和抽象工厂方法模式的battle

1.案例直接上手 在这个案例里面&#xff0c;我们会实现这个普通的工厂方法&#xff0c;并且对比这个普通工厂方法和我们直接创建对象的差别在哪里&#xff0c;为什么需要一个工厂&#xff1a; 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类&#xff1a; 两个发…...