当前位置: 首页 > 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版…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...