【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…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
