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

详解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中为什么要使用泛型 三.泛型的语法 四.泛型类的使用 五.泛型的编译机制&#xff08;擦除机制&#xff09; 六.泛型的上界 一.什么是泛型 泛型&#xff08;Generics&#xff09;是Java SE 5中引入的一个新特性&#xff0c;可以使Java中的类和方…...

数据结构算法-贪心算法

引言 贪心&#xff1a;人只要有 “需求“ &#xff0c;都会有有点“贪“&#xff0c; 这种“贪“是一种选择&#xff0c;或者“”取舍“ RTS&#xff08;即时战略&#xff09;游戏&#xff1a; 帝国时代里 首先确保拥有足够的人口 足够的粮食&#xff0c;足够的战略资源 足够的…...

【云备份】数据管理模块

文章目录 1. 数据管理模块要管理什么数据&#xff1f;2. 数据管理模块如何管理数据&#xff1f;3. 数据管理模块的具体实现BackupInfo 数据信息类NewBackupInfo —— 获取各项属性信息 DataManager 数据管理类构造函数析构函数insert —— 新增update —— 修改GetOneByURL——…...

C++ :const修饰成员函数

常函数&#xff1a; 常函数&#xff1a; 成员函数后加const后我们称为这个函数为常函数 常函数内不可以修改成员属性 成员属性声明时加关键字mutable后&#xff0c;在常函数中依然可以修改 属性可修改&#xff1a; class Person { public: void showPerson() …...

论文阅读:“Model-based teeth reconstruction”

文章目录 AbstractIntroductionTeeth Prior ModelData PreparationParametric Teeth Model Teeth FittingTeeth Boundary Extraction Reference Abstract 近年来&#xff0c;基于图像的人脸重建方法日趋成熟。这些方法可以捕捉整个面部或面部特定区域&#xff08;如头发、眼睛…...

Web 安全之证书透明(Certificate Transparency)详解

目录 证书透明性的概念 数字证书和颁发机构 证书透明的起源 证书透明的工作原理 证书透明的实现方法 证书透明的优点 浏览器和客户端对证书透明的支持情况 小结 证书透明&#xff08;Certificate Transparency, CT&#xff09;是网络安全领域中的一个重要概念&#xff…...

智能优化算法应用:基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蜻蜓算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蜻蜓算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…...

【古诗生成AI实战】之二——项目架构设计

[1] 项目架构 在我们深入古诗生成AI项目的具体实践之前&#xff0c;让我们首先理解整个项目的架构。本项目的代码流程主要分为三个关键阶段&#xff1a; 1、数据处理阶段&#xff1b;   2、模型训练阶段&#xff1b;   3、文本生成阶段。 第一步&#xff1a;在数据处理阶段…...

动态网页从数据库取信息,然后展示。

把数据库的驱动放在bin目录下。 通过servlet 读取数据库的内容&#xff0c;生成session,然后跨页面传给展示页。 package src;import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSe…...

单片机学习3——数码管

数码管&#xff0c;根据内部结构&#xff0c;可分为共阴极数码管和共阳极数码管。七段发光管加上一个小数点&#xff0c;共计8段。因此&#xff0c;我们对它编程的时候&#xff0c;刚好是用一个字节。 数码管的显示方式&#xff1a; 1&#xff09;静态显示&#xff1b; 2&…...

数据库表结构导出成Excel或Word格式

前言 该工具主要用于导出excel、word&#xff0c;方便快速编写《数据库设计文档》&#xff0c;同时可以快速查看表的结构和相关信息。 本博客仅作记录&#xff0c;最新源码已经支持多种数据库多种格式导出&#xff0c;有兴趣的可移步源码作者地址&#xff1a;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&#xff1f;Docker Hub vs. 私有RegistryDocker Hub&#xff1a;私有Registry&#xff1a; 如何构建私有Docker Registry&#xff1f;步骤一&#xff1a;安装Docker Registry步骤二&#xff1a;配置TLS&#xff08;可选&#xff09;步骤三&…...

leetcode 不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;…...

通俗易懂的spring Cloud;业务场景介绍 二、Spring Cloud核心组件:Eureka 、Feign、Ribbon、Hystrix、zuul

文章目录 通俗易懂的spring Cloud一、业务场景介绍二、Spring Cloud核心组件&#xff1a;Eureka三、Spring Cloud核心组件&#xff1a;Feign四、Spring Cloud核心组件&#xff1a;Ribbon五、Spring Cloud核心组件&#xff1a;Hystrix六、Spring Cloud核心组件&#xff1a;Zuul七…...

大数据预处理技术

文章目录 前言 大数据技术成为前沿专业 也是现在甚至未来的朝阳产业&#xff0c;大数据有分别是 数据预处理 数据存储 大数据处理和分析 数据可视化 部分组成 &#xff0c;大数据行业有数据则称王&#xff0c;大数据的核心是数据本身 怎么获取有价值的数据呢&#xff1f;本章讲…...

跳表的学习记录

跳表&#xff08;Skip List&#xff09;是一种数据结构&#xff0c;它通过在多个层次上添加额外的前向指针来提高有序数据的搜索效率。跳表与其他常见的有序数据结构&#xff08;如二叉搜索树、平衡树如AVL树和红黑树、B树等&#xff09;相比&#xff0c;具有其独特的优缺点&am…...

电子学会C/C++编程等级考试2022年09月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:统计误差范围内的数 统计一个整数序列中与指定数字m误差范围小于等于X的数的个数。 时间限制:5000 内存限制:65536输入 输入包含三行: 第一行为N,表示整数序列的长度(N <= 100); 第二行为N个整数,整数之间以一个空格分…...

如何使用nginx部署静态资源

Nginx可以作为静态web服务器来部署静态资源&#xff0c;这个静态资源是指在服务端真实存在&#xff0c;并且能够直接展示的一些文件数据&#xff0c;比如常见的静态资源有html页面、css文件、js文件、图片、视频、音频等资源相对于Tomcat服务器来说&#xff0c;Nginx处理静态资…...

lua的gc原理

lua垃圾回收(Garbage Collect)是lua中一个比较重要的部分。由于lua源码版本变迁&#xff0c;目前大多数有关这个方面的文章都还是基于lua5.1版本&#xff0c;有一定的滞后性。因此本文通过参考当前的5.3.4版本的Lua源码&#xff0c;希望对Lua的GC算法有一个较为详尽的探讨。 L…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

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

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

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...