详解Java中的泛型(泛型的语法,擦除机制,泛型的上界)

目录
一.什么是泛型
二.Java中为什么要使用泛型
三.泛型的语法
四.泛型类的使用
五.泛型的编译机制(擦除机制)
六.泛型的上界
一.什么是泛型
泛型(Generics)是Java SE 5中引入的一个新特性,可以使Java中的类和方法具有更广泛的类型范围。通俗的说,它使得我们可以在定义类和方法时指定一个或多个类型参数,从而可以在不考虑具体类型的情况下,代码中直接使用这些类型参数。泛型可以增强代码的安全性、可读性和可重用性。例如,可以使用泛型实现容器类(如ArrayList、HashMap)等。在使用泛型时,需要在编写代码时指定泛型类型,这样可以在编译期间检查代码的类型安全性。
二.Java中为什么要使用泛型
一般的类和方法,只能使用具体的类型::要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。
----- 来源《Java编程思想》对泛型的介绍
Java中的泛型是一种允许在编写代码时指定类型参数的能力。使用泛型可以使代码更加通用且类型安全。通过使用泛型,程序员可以编写一个方法或类,该方法或类在实例化时可以接受不同类型的参数。泛型是将数据类型参数化,进行传递这样可以减少代码的重复,并提高代码的可读性和可维护性。
假如我们要实现一个数组,使得其中能够存放任意数据类型的元素,想存放整形,又想存放字符型,又想存放引用型该怎么办呢?我们可以联想一下之前认识过的Object类,Object类是所有类的父类,那我们将数组置为Object类可以吗?
class MyArray {public Object[] array = new Object[10];public Object getPos(int pos) {return this.array[pos];}public void setVal(int pos,Object val) {this.array[pos] = val;}
}
public static void main(String[] args) {MyArray myArray = new MyArray();myArray.setVal(0, 10);//整形可以存放myArray.setVal(1, "hello");//字符串也可以存放String ret = myArray.getPos(1);//编译报错,原因是因为我们数组的类型是Object类型//但是我们这里接收的元素却是String类型//也就是说我们相当于进行了向下转型,所以这里会报错//如果我们进行强制转化就可以解决这个问题//String ret = (String) myArray.getPos(1);System.out.println(ret);}
我们会发现在这种情况下,整体的语法其实是不灵活的,虽然当前数组任何数据都可以存放,但是更多情况下,我们还是希望他只能够持有一种数据类型,而不是同时持有这么多类型。
所以泛型的主要目的就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时就需要把类型作为参数传递,需要什么类型,就传入什么类型。
三.泛型的语法
在充分认识了泛型的必要性和作用后,我们来看看如何使用它:在Java中,泛型的使用方式是通过在类名或方法名后面加上尖括号,然后在尖括号里指定类型参数。具体语法如下:
class 泛型类名称<类型形参列表> {// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {// 可以只使用部分类型参数
}
可以通过泛型实例化一个泛型对象
泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象MyArray<Integer> list = new MyArray<Integer>();
当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写
MyArray<Integer> list = new MyArray<>(); // 可以推导出实例化需要的类型实参为 Integer
泛型只能接受类,所有的基本数据类型必须使用包装类
四.泛型类的使用
对于我们刚才的数组,我们就可以如下设置为一个泛型数组
class MyArray<T> {public T[] array = (T[])new Object[10];//1//public T[] array;public T getPos(int pos) {return this.array[pos];}public void setVal(int pos,T val) {this.array[pos] = val;}
}
public static void main(String[] args) {MyArray<Integer> myArray1 = new MyArray<>();//2myArray1.setVal(0,10);myArray1.setVal(1,12);MyArray<String> myArray2 = new MyArray<>();//3myArray2.setVal(0,"hello");myArray2.setVal(1,"world");MyArray<Float> myArray3 = new MyArray<>();//4myArray3.setVal(0,1.23f);myArray3.setVal(1,3.14f);}
在上述代码块中
类名后的 <T> 代表占位符,表示当前类是一个泛型类,常用的其他名称有:
- E 表示 Element
- K 表示 Key
- V 表示 Value
- N 表示 Number
- T 表示 Type
- S, U, V 等等... ...
注释1处,不能new泛型类型的数组,也就是说下面这样的代码是错误的
T[] arrary = new T[5];//是不对的
注释2处,类型后加入 <Integer> 指定当前类型,注释3,4处同理
五.泛型的编译机制(擦除机制)
Java的类型擦除机制是指在编译期间将泛型的类型参数替换为其边界或Object类型,从而实现泛型代码运行时无需知晓实际类型参数,也就是说泛型的类型参数在运行时是被擦除了的。这个机制是为了兼容Java语言的旧版本,同时也可以减少代码重复,使得代码更加简洁。
举个例子来说,:
假如有一个泛型类List<T>,其中的T可以指定任何类型,但是在运行时,List<T>的实际类型是List<Object>。那么,当我们在使用List<T>时,编译器会自动擦除类型参数T,然后将List<T>替换为List<Object>,这样就可以在运行时使用Object类型来处理元素。
在编译期间,泛型类型参数String被擦除了,List<String>被替换成了List<Object>,而在运行时,get方法返回的是Object类型,需要强制转换为String类型,也就是说,我们无法在运行时获取到类型参数的具体值,因为编译器已经将其擦除了。
泛型到底是如何进行编译的?这曾经作为面试题进行考察过,泛型的语法实际上是非常复杂不容易理解的,我们需要借助他的字节码文件去观察,使用命令:javap -c 查看字节码文件

也就是说在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制
这个类型擦除机制也给开发带来了一些限制和挑战,比如不能在运行时获取泛型参数的具体类型,泛型数组的创建受到限制等。但是通过一些技巧和设计模式,我们可以在一定程度上绕过这些限制,让代码更加灵活和可扩展。
六.泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束,语法:
class 泛型类名称<类型形参 extends 类型边界> {//... ...
}
例如:
public class MyClass<T extends MyClass2> {// ...
}
上述代码中,泛型类型T的上界是MyClass2,这意味着在使用MyClass时,只能传入MyClass2或其子类作为T的实际类型参数。这样做可以确保在类型安全的前提下,使用泛型类型时具有更大的灵活性和可扩展性。
假设我们有一个泛型类Box<T>,我们希望确保这个类型参数T必须是实现了Comparable接口的类。我们可以使用泛型的上界<T extends Comparable<T>>来实现这个目标,示例代码如下:
public class Box<T extends Comparable<T>> {private T value;public Box(T value) {this.value = value;}public T getValue() {return value;}public boolean isGreaterThan(Box<T> otherBox) {return value.compareTo(otherBox.getValue()) > 0;}
}
在这个示例中,我们使用<T extends Comparable<T>>来定义类型参数上界,确保T必须是实现了Comparable接口的类。这样,我们就可以在isGreaterThan()方法中使用value.compareTo()方法来比较value字段和另一个Box对象的值了。
本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!
如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!
有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见![]()
相关文章:
详解Java中的泛型(泛型的语法,擦除机制,泛型的上界)
目录 一.什么是泛型 二.Java中为什么要使用泛型 三.泛型的语法 四.泛型类的使用 五.泛型的编译机制(擦除机制) 六.泛型的上界 一.什么是泛型 泛型(Generics)是Java SE 5中引入的一个新特性,可以使Java中的类和方…...
数据结构算法-贪心算法
引言 贪心:人只要有 “需求“ ,都会有有点“贪“, 这种“贪“是一种选择,或者“”取舍“ RTS(即时战略)游戏: 帝国时代里 首先确保拥有足够的人口 足够的粮食,足够的战略资源 足够的…...
【云备份】数据管理模块
文章目录 1. 数据管理模块要管理什么数据?2. 数据管理模块如何管理数据?3. 数据管理模块的具体实现BackupInfo 数据信息类NewBackupInfo —— 获取各项属性信息 DataManager 数据管理类构造函数析构函数insert —— 新增update —— 修改GetOneByURL——…...
C++ :const修饰成员函数
常函数: 常函数: 成员函数后加const后我们称为这个函数为常函数 常函数内不可以修改成员属性 成员属性声明时加关键字mutable后,在常函数中依然可以修改 属性可修改: class Person { public: void showPerson() …...
论文阅读:“Model-based teeth reconstruction”
文章目录 AbstractIntroductionTeeth Prior ModelData PreparationParametric Teeth Model Teeth FittingTeeth Boundary Extraction Reference Abstract 近年来,基于图像的人脸重建方法日趋成熟。这些方法可以捕捉整个面部或面部特定区域(如头发、眼睛…...
Web 安全之证书透明(Certificate Transparency)详解
目录 证书透明性的概念 数字证书和颁发机构 证书透明的起源 证书透明的工作原理 证书透明的实现方法 证书透明的优点 浏览器和客户端对证书透明的支持情况 小结 证书透明(Certificate Transparency, CT)是网络安全领域中的一个重要概念ÿ…...
智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜻蜓算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…...
【古诗生成AI实战】之二——项目架构设计
[1] 项目架构 在我们深入古诗生成AI项目的具体实践之前,让我们首先理解整个项目的架构。本项目的代码流程主要分为三个关键阶段: 1、数据处理阶段; 2、模型训练阶段; 3、文本生成阶段。 第一步:在数据处理阶段…...
动态网页从数据库取信息,然后展示。
把数据库的驱动放在bin目录下。 通过servlet 读取数据库的内容,生成session,然后跨页面传给展示页。 package src;import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSe…...
单片机学习3——数码管
数码管,根据内部结构,可分为共阴极数码管和共阳极数码管。七段发光管加上一个小数点,共计8段。因此,我们对它编程的时候,刚好是用一个字节。 数码管的显示方式: 1)静态显示; 2&…...
数据库表结构导出成Excel或Word格式
前言 该工具主要用于导出excel、word,方便快速编写《数据库设计文档》,同时可以快速查看表的结构和相关信息。 本博客仅作记录,最新源码已经支持多种数据库多种格式导出,有兴趣的可移步源码作者地址:https://gitee.co…...
School training competition ( Second )
A. Medium Number 链接 : Problem - 1760A - Codeforces 就是求三个数的中位数 : #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \nusing namespace std; typedef long long LL; const int N 2e510;inline void …...
深度解析 Docker Registry:构建安全高效的私有镜像仓库
文章目录 什么是Docker Registry?Docker Hub vs. 私有RegistryDocker Hub:私有Registry: 如何构建私有Docker Registry?步骤一:安装Docker Registry步骤二:配置TLS(可选)步骤三&…...
leetcode 不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n 3 输出:5 示例 2: 输入:n 1 输出:…...
通俗易懂的spring Cloud;业务场景介绍 二、Spring Cloud核心组件:Eureka 、Feign、Ribbon、Hystrix、zuul
文章目录 通俗易懂的spring Cloud一、业务场景介绍二、Spring Cloud核心组件:Eureka三、Spring Cloud核心组件:Feign四、Spring Cloud核心组件:Ribbon五、Spring Cloud核心组件:Hystrix六、Spring Cloud核心组件:Zuul七…...
大数据预处理技术
文章目录 前言 大数据技术成为前沿专业 也是现在甚至未来的朝阳产业,大数据有分别是 数据预处理 数据存储 大数据处理和分析 数据可视化 部分组成 ,大数据行业有数据则称王,大数据的核心是数据本身 怎么获取有价值的数据呢?本章讲…...
跳表的学习记录
跳表(Skip List)是一种数据结构,它通过在多个层次上添加额外的前向指针来提高有序数据的搜索效率。跳表与其他常见的有序数据结构(如二叉搜索树、平衡树如AVL树和红黑树、B树等)相比,具有其独特的优缺点&am…...
电子学会C/C++编程等级考试2022年09月(二级)真题解析
C/C++等级考试(1~8级)全部真题・点这里 第1题:统计误差范围内的数 统计一个整数序列中与指定数字m误差范围小于等于X的数的个数。 时间限制:5000 内存限制:65536输入 输入包含三行: 第一行为N,表示整数序列的长度(N <= 100); 第二行为N个整数,整数之间以一个空格分…...
如何使用nginx部署静态资源
Nginx可以作为静态web服务器来部署静态资源,这个静态资源是指在服务端真实存在,并且能够直接展示的一些文件数据,比如常见的静态资源有html页面、css文件、js文件、图片、视频、音频等资源相对于Tomcat服务器来说,Nginx处理静态资…...
lua的gc原理
lua垃圾回收(Garbage Collect)是lua中一个比较重要的部分。由于lua源码版本变迁,目前大多数有关这个方面的文章都还是基于lua5.1版本,有一定的滞后性。因此本文通过参考当前的5.3.4版本的Lua源码,希望对Lua的GC算法有一个较为详尽的探讨。 L…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果