【JavaSE】泛型
系列文章目录
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 系列文章目录
- 前言
- 一、pandas是什么?
- 二、使用步骤
- 1.引入库
- 2.读入数据
- 总结
前言
学习泛型之前请大家先详细地了解一下,关于Java当中的包装类和Object类的概念以及包装类当中的自动装箱和自动拆箱是什么,如果这部分内容不理解的话,泛型当中的很多细节可能无法理解,这篇文章集中讲解泛型当中的重难点,对于简单的细节不做介绍。
一、什么是泛型
1、基础概念
泛型是一种在编程语言中实现参数化类型的机制,它允许在定义类、接口、方法时使用类型参数,以便在使用时指定具体的类型。Java中引入了泛型的概念,它提供了编译时的类型检查,并允许在编写通用代码时指定具体的数据类型。
2、主要特点
1)参数化类型:泛型允许类、接口、方法在定义时使用参数,这些参数可以在使用时被具体的类型替代。
2)类型安全:泛型提供了编译时的类型检查机制,避免了在运行时出现类型转换异常。这样,开发者在编写代码时就能发现并修复类型相关的错误。
3)代码复用:泛型增加了代码的灵活性和复用性。通用的算法或数据结构可以用于处理各种类型的数据,而不需要为每种类型都编写相似的代码。
3、泛型语法
在Java中,泛型使用尖括号(<>)来声明类型参数。例如:
public class Box<T> {private T value;public Box(T value) {this.value = value;}public T getValue() {return value;} }在上面的例子中,Box 是一个泛型类,其中 表示类型参数。T 是一个占位符,它会在实例化时被具体的类型替代。
使用泛型的例子如下:
// 创建一个存储整数的Box对象 Box<Integer> integerBox = new Box<>(42); int intValue = integerBox.getValue(); // 不需要进行类型转换,编译器已经检查过了// 创建一个存储字符串的Box对象 Box<String> stringBox = new Box<>("Hello, Generics!"); String stringValue = stringBox.getValue(); // 同样不需要进行类型转换在这个例子中,Box 类被实例化两次,分别用于存储整数和字符串,而不需要为每一种类型编写不同的类。这样就实现了通用性和代码复用。泛型的强大之处在于它可以适用于各种数据类型,提高了代码的灵活性和可维护性。
二、为什么需要泛型
1、引出泛型:
我们可以通过引入泛型来实现一个通用的类,使其能够存放任何类型的数据,并提供方法获取数组中指定下标的值。以下是一个简单的示例:
public class GenericArray<T> {private T[] array;// 构造方法,初始化泛型数组public GenericArray(int size) {// 创建泛型数组的通用方式是使用 Object 类型的数组,然后进行强制类型转换this.array = (T[]) new Object[size];}// 设置数组指定下标的值public void set(int index, T value) {array[index] = value;}// 获取数组指定下标的值public T get(int index) {return array[index];}public static void main(String[] args) {// 创建一个存放整数的数组GenericArray<Integer> intArray = new GenericArray<>(5);intArray.set(0, 42);intArray.set(1, 15);// 获取数组中指定下标的值int valueAtIndex1 = intArray.get(1);System.out.println("Value at index 1: " + valueAtIndex1);// 创建一个存放字符串的数组GenericArray<String> stringArray = new GenericArray<>(3);stringArray.set(0, "Hello");stringArray.set(1, "Generics");// 获取数组中指定下标的值String valueAtIndex0 = stringArray.get(0);System.out.println("Value at index 0: " + valueAtIndex0);} }在这个示例中,GenericArray 类是一个泛型类,它使用类型参数 T 表示数组中元素的类型。构造方法中创建了一个 Object 类型的数组,然后进行强制类型转换。通过泛型,我们可以在使用该类时指定存放的数据类型,从而实现了通用性。
2、泛型擦除
Java中的擦除机制(Type Erasure)是指在编译时期,泛型类型信息会被擦除,T这个占位符会被全部替换成为Object或者是它的上界,而在运行时,Java虚拟机将不再保留泛型类型的具体信息。这是为了向后兼容性,因为在引入泛型之前的Java版本中,是没有泛型概念的。
1)类型参数擦除:在编译时,泛型类型的类型参数将被擦除,替换为Object,例如对于List,编译后的代码中的类型信息将被替换为List<Object>。
2)泛型数组限制:由于擦除机制,不能直接创建泛型数组。例如,以下代码是非法的:
List<String>[] arrayOfLists = new ArrayList<String>[10];编译器会发出警告,因为在运行时,无法获得泛型数组的确切类型信息。通常,可以使用原始类型的数组,然后进行强制类型转换,但这可能导致运行时异常。
擦除机制的主要目标是确保与没有泛型的旧代码的兼容性,并允许在运行时处理泛型代码。然而,擦除也带来了一些挑战,尤其是在编写需要在运行时访问泛型类型信息的代码时。在这种情况下,通常需要使用反射或其他技术来处理擦除后的类型。
在Java中,T[] ts = new T[5]; 是不允许的,因为直接创建泛型数组是违反Java语言规范的。泛型在Java中是通过擦除实现的,即在运行时泛型信息会被擦除,编译器会将泛型类型替换为原始类型或其边界。
T[] ts = new T[5];那么在运行时,它实际上会被替换为:
Object[] ts = new Object[5];这似乎是合理的,但问题在于泛型的目的是提供类型安全性,而直接使用 Object[] 会失去泛型的好处。你可以轻松地将任意对象放入 Object[] 中,而不会得到编译器的警告。这就违背了使用泛型的初衷,因为泛型的目标是在编译时提供更严格的类型检查。
因此,为了维护类型安全性,Java禁止直接创建泛型数组。相反,你应该使用集合类或其他类型安全的数据结构,或者在需要时使用非泛型数组,并在运行时进行必要的类型转换。
3、为什么不能实例化泛型数组
因为一个T类型的数组也就是T[] array = new T[];或者:
class MyArray<T> { public T[] array = (T[])new Object[10]; public T getPos(int pos) { return this.array[pos]; } public void setVal(int pos,T val) { this.array[pos] = val; } public T[] getArray() { return array; } } public static void main(String[] args) { MyArray<Integer> myArray1 = new MyArray<>(); Integer[] strings = myArray1.getArray(); }泛型擦除之后,这个泛型又没有设置上界(泛型的上界我们一会介绍),T占位符全部被替换成Object,也就是可以是任意类型,这个数组里面可以存放任意类型,编译器认为这是不安全的,而且数组存放什么内容是运行时决定的,编译器无法对其进行限制,所以Java的编译器不允许程序员做这样危险的操作。
尤其是这行代码:
Integer[] strings = myArray1.getArray();这个数组里面可能存放了任意类型的数据,而这个时候又要把这个数组赋值给一个Integer类型的数组,编译器一定报错。
三、泛型上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。1、泛型语法class 泛型类名称<类型形参 extends 类型边界> { ... }2、实例
public class MyArray<E extends Number> { ... }只接受 Number 的子类型作为 E 的类型实参MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的子类型 MyArray<String> l2; // 编译错误,因为 String 不是 Number 的子类型如果没有指定类型边界 E,可以视为 E extends Object。
四、泛型方法
泛型方法是一种在方法级别使用泛型的方式,允许在方法中使用具有独立类型参数的泛型。通过泛型方法,我们可以编写更灵活、通用的代码,而不受限于整个类的泛型类型参数。下面是一个简单的泛型方法的例子:
public class GenericMethodExample {// 泛型方法,接收一个数组并返回数组中的最大值//这里是泛型的上界代表着这个方法必须实现Comparable接口public static <T extends Comparable<T>> T findMax(T[] array) {if (array == null || array.length == 0) {return null; // 返回 null 表示数组为空}T max = array[0];for (T element : array) {if (element.compareTo(max) > 0) {max = element;}}return max;}public static void main(String[] args) {// 使用泛型方法找到整数数组的最大值Integer[] intArray = {3, 7, 1, 9, 4};Integer maxInt = findMax(intArray);System.out.println("Max Integer: " + maxInt);// 使用泛型方法找到字符串数组的最大值String[] stringArray = {"apple", "orange", "banana", "grape"};String maxString = findMax(stringArray);System.out.println("Max String: " + maxString);} }findMax()方法是一个泛型方法,使用 > 来声明泛型类型参数。这表示传入的类型 T 必须实现 Comparable 接口(泛型的上界),以便进行比较。
方法使用了泛型类型参数
T 来定义数组和返回值的类型。这样,findMax 方法可以接受不同类型的数组,包括整数、浮点数、字符串等。
在 main 方法中,我们分别使用 findMax 方法找到整数数组和字符串数组的最大值。
通过使用泛型方法,我们可以避免为每个类型都编写一个专门的方法,使代码更加灵活和通用。泛型方法通常在集合类、算法类等地方得到广泛应用。
总结
泛型的学习主要是为了我们更好地学习数据结构,所以这部分的内容大家会用就可以,主要通过上手实践来解决问题。
相关文章:
【JavaSE】泛型
系列文章目录 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 前言 学习泛型之前请大家先详细地了解一下,关于Java…...
APS(高级计划与调度系统)难度超高,ERP在它面前就是弟弟。
一、APS定义和功能模块 APS系统是Advanced Planning and Scheduling System(高级计划与调度系统)的缩写。它是一种计划和调度管理软件系统,旨在帮助企业优化生产计划和资源调度,提高生产效率和响应能力。 APS系统利用先进的算法和…...
ArmV8架构
Armv8/armv9架构入门指南 — Armv8/armv9架构入门指南 v1.0 documentation 上面只是给了一个比较好的参考文档 其他内容待补充...
[论文笔记] Open-sora 2、视频数据集介绍 MSR-VTT
MSR-VTT COVE - Computer Vision Exchange 论文参考:https://www.microsoft.com/en-us/research/wp-content/uploads/2016/06/cvpr16.msr-vtt.tmei_-1.pdf 用于视频理解的大规模视频基准,特别是将视频翻译为文本的新兴任务。这是通过从商业视频搜索引擎收集 257 个热门查询…...
【Windows 常用工具系列 14 -- windows 网络驱动映射】
文章目录 windows 网络驱动映射 windows 网络驱动映射 映射网络驱动器的意思是将局域网中的某个目录映射成本地驱动器号。 在windows上将服务器目录映射到本地盘: 进入到服务器执行下面命令既可以看到对应的 IP地址: 将对应的IP地址填入上图中。 映…...
Java中使用Jsoup实现网页内容爬取与Html内容解析并使用EasyExcel实现导出为Excel文件
场景 Pythont通过request以及BeautifulSoup爬取几千条情话: Pythont通过request以及BeautifulSoup爬取几千条情话_爬取情话-CSDN博客 Node-RED中使用html节点爬取HTML网页资料之爬取Node-RED的最新版本: Node-RED中使用html节点爬取HTML网页资料之爬…...
闫震海:腾讯音乐空间音频技术的发展和应用 | 演讲嘉宾公布
一、3D 音频 3D 音频分论坛将于3月27日同期举办! 3D音频技术不仅能够提供更加真实、沉浸的虚拟世界体验,跨越时空的限制,探索未知的世界。同时,提供更加丰富、立体的情感表达和交流方式,让人类能够更加深入地理解彼此&…...
Java基础 - 6 - 面向对象(二)
Java基础 - 6 - 面向对象(一)-CSDN博客 二. 面向对象高级 2.1 static static叫做静态,可以修饰成员变量、成员方法 2.1.1 static修饰成员变量 成员变量按照有无static修饰,分为两种:类变量、实例变量(对象…...
SpringCloud-MQ消息队列
一、消息队列介绍 MQ (MessageQueue) ,中文是消息队列,字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。消息队列是一种基于生产者-消费者模型的通信方式,通过在消息队列中存放和传递消息,实现了不同组件、服务或系统…...
代码随想录算法训练营第三十八天|509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
509. 斐波那契数 刷题https://leetcode.cn/problems/fibonacci-number/description/文章讲解https://programmercarl.com/0509.%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE视频讲解https://www.bilibili.com/video/BV…...
[python] 代码工具箱
在 Python 3 的开发过程中,有一些小而实用的工具包可以帮助减轻开发负担,提升工作效率。这些工具包通常专注于解决特定问题或提供特定功能,使代码更简洁和可维护。以下是一些常用的工具包,可以简化开发过程: backoff&a…...
Linux——网络基础
计算机网络背景 网络发展 独立模式: 计算机之间相互独立 在早期的时候,计算机之间是相互独立的,此时如果多个计算机要协同完成某种业务,那么就只能等一台计算机处理完后再将数据传递给下一台计算机,然后下一台计算机再进行相应…...
Vue:双token无感刷新
文章目录 初次授权与发放Token:Access Token的作用:Refresh Token的作用:无感刷新:安全机制:后端创建nest项目AppController 添加login、refresh、getinfo接口创建user.dto.tsAppController添加模拟数据 前端Hbuilder创…...
实现一个作用域插槽的场景
vue项目中,插槽slot有三种分别是:默认插槽、具名插槽、作用域插槽。默认插槽和具名插槽在平时的开发中用的比较多,作用域插槽用的相对较少,以前我对作用域插槽不是很理解,现在理解了一下。下面通过代码来实现一个作用域…...
Qt QPainter的使用方法
重点: 1.QPainter在QWidget窗口的paintEvent中使用。 2.QPainter通常涉及到设置画笔、设置画刷、绘图(QPen、QBrush、drawxx)三个流程。 class Widget : public QWidget {Q_OBJECTprotected:void paintEvent(QPaintEvent *event) Q_DEC…...
低代码:数智化助力新农业发展
随着科技的飞速发展和数字化转型的深入推进,低代码开发平台正逐渐成为软件开发的热门话题。尤其在农业领域,低代码技术为传统农业注入了新的活力,助力新农业实现高效、智能的发展。 低代码开发平台的概念与特点 随着科技的飞速发展࿰…...
3d模型怎么镜像?3d模型镜像的步骤---模大狮模型网
在3D建模软件中,对3D模型进行镜像操作通常是指沿着某个轴线(如X、Y、Z轴)进行镜像翻转,使模型在该轴线的一侧产生对称的镜像效果。以下是在常见的3D建模软件中对3D模型进行镜像的一般步骤: 3d模型镜像步骤: 选择模型:…...
笔记本hp6930p安装Android-x86补记
在上一篇日记中(笔记本hp6930p安装Android-x86避坑日记-CSDN博客)提到hp6930p安装Android-x86-9.0,无法正常启动,本文对此再做尝试,原因是:Android-x86-9.0不支持无线网卡,需要在BIOS中关闭WLAN…...
为什么MySQL中多表联查效率低,连接查询实现的原理是什么?
MySQL中多表联查效率低的原因主要涉及到以下几个方面: 数据量大: 当多个表通过连接查询时,如果这些表的数据量很大,那么查询就需要处理更多的数据,这自然会降低查询效率。 连接操作复杂性: 连接查询需要对参与连接的每个表中的数…...
从下一代车规MCU厘清存储器的发展(2)
目录 1.概述 2.MCU大厂的选择 2.1 瑞萨自研STT-MRAM 2.2 ST专注PCM 2.3 英飞凌和台积电联手RRAM 2.4 NXP如何计划eNVM 3.小结 1.概述 上篇文章,我们简述了当前主流的存储器技术,现在我们来讲讲各大MCU大厂的技术选择 2.MCU大厂的选择 瑞萨日…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
