【Java基础】泛型
文章目录
- 泛型
- 一、概述
- 二、泛型的使用
- 1、类
- 2、方法
- 3、接口
- 三、泛型通配符
- 1、<?>
- 2、<? extends T>
- 3、<? super T>
- 四、泛型的擦除
- 1、泛型的擦除
- 2、泛型边界的擦除
- 3、无法实例化泛型类型
泛型
一、概述
泛型(Generic)是一种机制,允许你编写与数据类型无关的代码,增加代码的灵活性和可重用性。
- 泛型在定义的时候不具体,使用的时候才变得具体。在使用的时候确定泛型的具体数据类型。
泛型的作用:
- 安全性:编译时检查类型,将运行时期的
ClassCastException,转移到编译时期的编译失败。 - 灵活性:使类型参数化,可以预先地使用未知的类型,让设计的代码更通用灵活。
- 重用性:一个泛型类或方法可以处理多种数据类型,减少代码重复。
- 维护性:泛型代码通常更清晰,容易理解和维护。
注意事项:
- 泛型只能在编译阶段起作用,到了运行阶段就会被擦除。
- 泛型只能是引用数据类型,不能是 基本数据类型。
- 泛型在使用时指定实际的类型,如果不指定默认为Object类型。
二、泛型的使用
1、类
定义:类名之后
// 泛型一般用大写的单个字母表示,可以定义多个泛型,使用逗号分隔。
修饰符 class 类名<A, B, C> {}
使用:在类中使用,可以作为 实例方法 的 参数 和 返回值(静态方法不支持)
class Example<T> {// 作为实例方法的参数类型public void show(T t) {System.out.println(t);}// 作为实例方法的返回值类型public T get(int index) {return null;}// 静态方法 不能使用 类上定义的泛型// public static void test1(T t) {...}// public static T test2(int index) {...}
}
指定类型:创建对象时
public class Test {public static void main(String[] args) {// 在创建对象时,根据需要指定泛型的类型DataShow<String> ds = new DataShow<>();ds.show("Hello"); }
}
2、方法
定义:返回值之前
修饰符 <T> 返回值类型 方法名(T t) {}
使用:在方法内部使用
class Example {public static <T> void show(T t) {// 在方法内部使用System.out.println("t = " + t);}// 不同方法的泛型名称可以一致public static <T> void show2(T t) {}
}
指定类型:调用方法时,根据传参的类型
public class Test {public static void main(String[] args) {show(100); // T -> Integershow("Hello"); // T -> String}
}
3、接口
定义:接口名之后
public interface 接口名<E> {}
使用:作为 接口方法 的 参数 或 返回值
public interface Example<T> {void method1(T t);T method2();
}
指定类型:
1、定义接口的实现类时,确定泛型的类型
public class ExampleChild1 implements Example<String>{@Overridepublic void method1(String s) {System.out.println(s);}@Overridepublic String method2() {return null;}
}
2、定义接口的实现类时,继续沿用泛型
public class ExampleChild2<T> implements Example<T> {@Overridepublic void method1(T t) {System.out.println(t);}@Overridepublic T method2() {return null;}
}
在创建接口的实现类对象时,确定泛型的类型
public class Test {public static void main(String[] args) {ExampleChild2<String> exampleChild2 = new ExampleChild2<>();exampleChild2.method1("hello");String str = exampleChild2.method2();}
}
三、泛型通配符
泛型通配符
<?>,常用于泛型方法和类中,帮助实现更加灵活和通用的类型操作。
1、<?>
<?>:表示任意类型,适用于我们不关心具体类型的场景。(只能使用Object类中的共性方法)
public void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}
}
使用举例
public class Test {public static void main(String[] args) {List<Integer> integerList = new ArrayList<>();integerList.add(1);integerList.add(2);// 使用泛型方法printList(integerList);}public static void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}}
}
2、<? extends T>
<? extends T>:表示 T 或 T 的子类型,适用于读取操作。(可以使用父类T 中的公共方法)
public void processNumbers(List<? extends Number> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L; // Long extends Numbernumbers.add(a); // error,Java 的泛型系统为了类型安全,不允许向这样的列表中添加特定类型的元素(除 null 外)。
}
public <T extends Number> void processNumbers(List<T> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L; // Long extends Numbernumbers.add(a); // error
}
使用举例
public class Test {public static void main(String[] args) {List<Integer> integerList = new ArrayList<>();integerList.add(1);integerList.add(2);// 使用泛型方法printNumbers(integerList);}public static <T extends Number> void printNumbers(List<T> list) {for (T number : list) {System.out.println(number);}}
}
3、<? super T>
<? super T>:表示 T 或 T 的父类型,适用于写入操作。
public void addNumbers(List<? super Integer> list) {list.add(1); // 可以安全地添加 Integer 类型的元素list.add(2); // 也可以添加其他 Integer 类型的元素
}
// 编译错误! `super` 只能用在 泛型方法 或 类中的方法参数 中来指定一个类型范围。
public <T super Integer> void addNumbers(List<T> list) {...}
使用举例
public class Test {public static void main(String[] args) {List<Number> numbers = new ArrayList<>();// 使用泛型方法addNumbers(numbers);System.out.println(numbers);}public static void addNumbers(List<? super Integer> list) {list.add(1); // 可以添加 Integer 类型的对象list.add(2); // 可以添加 Integer 类型的对象}
}
四、泛型的擦除
泛型的擦除是指,在编译期间,Java 编译器会将泛型信息擦除掉,泛型类型参数会被替换为其限定类型。
- 默认情况下,泛型类型参数会被替换为
Object - 如果泛型有上限,如
T extends Number,擦除后会使用上限类型(Number)。
例如:
List<String>和List<Integer>在编译后都会被擦除为List。List<T extends Number>会擦除为List<Number>。
泛型擦除的主要目的是为了 兼容 Java 的早期版本 和 简化虚拟机的实现。
- 泛型擦除将泛型类型转换为
Object或其超类,从而使得 泛型代码 可以与 旧版本的 Java 代码 相互操作。 - 泛型擦除意味着 泛型的具体类型(
T)在字节码中不可见,保持向后兼容性的同时,避免对字节码格式进行重大修改。
但是,这也会导致一些泛型相关的信息在运行时不可用,需要在编写泛型代码时注意擦除造成的影响。
1、泛型的擦除
public class GenericMethodExample {// 泛型方法 在擦除后会变成 `print(Object data)` public <T> void print(T data) {System.out.println(data);}// 原始类型的方法 -> 编译错误!因为与擦除后的泛型方法冲突了public void print(Object data) {System.out.println(data);}
}
public class GenericMethodExample {// 泛型方法 在擦除后会变成 `print(Object data)` public <T> void print(T data) {System.out.println(data);}// 原始类型的方法 -> 编译通过!因为泛型默认擦除为 Object,这里是 String,重载public void print(String data) {System.out.println(data);}
}
2、泛型边界的擦除
public void processNumbers(List<? extends Number> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L; // Long extends Numbernumbers.add(a); // error
}
List<T extends Number>在编译后会被擦除为List<Number>。
public <T extends Number> void processNumbers(List<T> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L; // Long extends Numbernumbers.add(a); // error
}
- 泛型参数
T在运行时被擦除为Number类型。
3、无法实例化泛型类型
public class GenericInstantiationExample<T> {private T instance;public GenericInstantiationExample() {// 编译错误:无法直接实例化泛型类型// instance = new T(); // 错误}public GenericInstantiationExample(Class<T> clazz) {try {instance = clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {e.printStackTrace();}}
}
new T()在编译时会引发错误,因为T的实际类型在运行时未知。- 可以使用反射(通过传递
Class<T>对象)来实例化对象。
相关文章:
【Java基础】泛型
文章目录 泛型一、概述二、泛型的使用1、类2、方法3、接口 三、泛型通配符1、<?>2、<? extends T>3、<? super T> 四、泛型的擦除1、泛型的擦除2、泛型边界的擦除3、无法实例化泛型类型 泛型 一、概述 泛型(Generic)是一种机制&a…...
STL-vector练习题
118. 杨辉三角 思路: 杨辉三角有以下性质使我们要用到的: ● 每行数字左右对称,由 1 开始逐渐变大再变小,并最终回到 1。 ● 第 n 行(从 0 开始编号)的数字有 n1 项,前 n 行共有 2n(n1)个数。…...
Leetcode 165. 比较版本号(Medium)
给你两个 版本号字符串 version1 和 version2 ,请你比较它们。版本号由被点 . 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。 比较版本号时,请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字符串的修订号较少,…...
Android 12 Launcher3 去掉Hotseat
1.概述 在12.0 产品定制化开发中 由产品需求Launcher3 页面布局的原因,要求Launcher3 需要去掉Hotseat 不显示Hotseat下面几个图标,而做满屏app的显示,从而达到美观的效果,下面就来分析去掉Hotseat从而实现这个功能 2.Launcher3 …...
Nginx实用篇:实现负载均衡、限流与动静分离
Nginx实用篇:实现负载均衡、限流与动静分离 | 原创作者/编辑:凯哥Java | 分类:Nginx学习系列教程 Nginx 作为一款高性能的 HTTP 服务器及反向代理解决方案,在互联网架构中扮演着至关重要的角色。它…...
python | Python中的类多态:方法重写和动态绑定
本文来源公众号“python”,仅用于学术分享,侵权删,干货满满。 原文链接:Python中的类多态:方法重写和动态绑定 多态(Polymorphism)是面向对象编程的核心特性之一,它允许同一接口在…...
Rust编写Windows服务
文章目录 Rust编写Windows服务一:Windows服务程序大致原理二:Rust中编写windows服务三:具体实例 Rust编写Windows服务 编写Windows服务可选语言很多, 其中C#最简单。本着练手Rust语言,尝试用Rust编写一个服务。 一:Win…...
MATLAB 从 R2024B 开始支持树莓派 5
树莓派(Raspberry Pi)系列是一系列基于单板计算机的微型电脑,由英国的树莓派基金会于 2012 年开始发布。它的目标是提供一个低成本、易于学习和玩耍的平台,用于教育和初学者学习计算机科学和编程。 目前市面上,最新最…...
MiniBlogum项目简介
MiniBlogum项目简介 文章目录 MiniBlogum项目简介一、引言二、技术栈与开发环境三、主要功能(一)用户注册与登录(二)查看当前登录用户/作者头像、昵称、Gitee仓库地址(三)查看博客列表(四&#…...
如何用 OBProxy 实现 OceanBase 的最佳路由策略
引言 OBProxy,即OceanBase Database Proxy,也简称为ODP,是 OceanBase数据库的专属服务代理。通过应用OBProxy,由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽,从而使得访问分布式数据库的体验如同访问单机数…...
new/delete和malloc/free到底有什么区别
new和malloc 文章目录 new和malloc前言一、属性上的区别二、使用上的区别三、内存位置的区别四、返回类型的区别五、分配失败的区别六、扩张内存的区别七、系统调度过程的区别总结 前言 new和malloc的知识点,作为一个嵌入式工程师是必须要了解清楚的。new和malloc的…...
Flutter启动无法运行热重载
当出现这种报错时,大概率是flutter的NO_Proxy出问题。 请忽略上面的Android报错因为我做的是windows开发这个也就不管了哈,解决下面也有解决报错的命令大家执行一下就行。 着重说一下Proxy的问题, 我们看到提示NO_PROXY 没有设置。 这个时候我…...
CSS调整背景
一、设置背景颜色 通过 background-color 属性指定,值可以是十六进制 #ffffff,也可以是rgb(0, 255, 255),或是颜色名称 "red" div {background-color: red; /* 通过颜色名称设置 */background-color: #ff0000; /* 通过十六进制设…...
FinalShell连接Linux服务器并解决反复输入密码问题
FinalShell是一款由国人开发的SSH客户端工具,它支持多平台,包括Windows、Mac OS X和Linux。FinalShell主要用于一体化服务器管理,它不仅是一个SSH客户端,还具备强大的开发和运维功能,能够充分满足开发和运维的需求。 本…...
实用类工具!分享6款AI论文一键生成器免费8000字
在当前的学术研究和写作领域,AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。千笔-AIPassPaper是一款备受推荐的AI论文一键生成器。 千笔-AIPassPaper是一个一站式…...
vue使用TreeSelect设置带所有父级节点的回显
Element Plus的el-tree-select组件 思路: 选中节点时,给选中的节点赋值 pathLabel,pathLabel 为函数生成的节点名字拼接,数据源中不包含。 在el-tree-select组件中设置 props“{ label: ‘pathLabel’ }” 控制选中时input框中回…...
智能机巢+无人机:自动化巡检技术详解
智能机巢与无人机的结合,在自动化巡检领域展现出了巨大的潜力和优势。以下是对这一技术的详细解析: 一、智能机巢概述 智能机巢,也被称为无人机机场或无人机机巢,是专门为无人机提供停靠、充电、维护等服务的智能化设施。它不仅…...
摩托车加装车载手机充电usb方案/雅马哈USB充电方案开发
长途骑行需要给手机与行车记录仪等设备供电,那么,加装USB充电器就相继在两轮电动车上应用起来了。摩托车加装usb充电方案主要应用于汽车、电动自行车、摩托车、房车、渡轮、游艇等交通工具。提供电动车USB充电器方案/摩托车加装usb充电方案/渡轮加装usb充…...
进阶岛 任务3: LMDeploy 量化部署进阶实践
进阶岛 任务3: LMDeploy 量化部署进阶实践 任务:https://github.com/InternLM/Tutorial/blob/camp3/docs/L2/LMDeploy/task.md 使用结合W4A16量化与kv cache量化的internlm2_5-1_8b-chat模型封装本地API并与大模型进行一次对话,作业截图需包…...
vue 使用jszip,file-saver下载压缩包,自定义文件夹名,文件名打包下载为zip压缩包文件,全局封装公共方法使用。
记录一下后台管理全局封装一个压缩包下载方法,文件夹名自定义,文件名自定义,压缩包名自定义。 安装必要的库 npm install jszip npm install file-saver自定义一个公共方法全局注入 页面使用 /** 下载按钮操作 */handleDownload() {const i…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...
