泛型
为什么使用泛型
- 意味着编写的代码可以被很多不同类型的对象所重用
- 类型参数-->可以让程序员知道数组列表类型
- 代码示例
ArrayList<String> arr = new ArrayList<>();
- 后面的尖括号省略类型可以推断出来
就相当于给一个瓶子贴上了标签,让人知道里面装的是什么
优点在于使得程序具有更好的可读性和安全性
定义一个简单泛型类
- 代码示例
//泛型类,T为类型变量
public class People<T>{
//泛型属性
private T num;
//泛型 方法
public T getNum(){
//....
}
}
- 类型变量使用大写形式,且短
- 使用
E
表示集合的元素类型 - 使用
K
表示关键字类型 - 使用
V
表示值类型 - 使用
T
表示可以为任意类型
//例如
People<String> p = new People<>(); //可以是String类型
People<Student> p = new People<>(); //也可以是自定义的Student类型
- 泛型类可以看做是普通类的工厂
泛型方法
- 泛型方法可以定义在泛型类中也可以定义在普通类中
class Student{
public static <T> T getName(T...a){
//.......
}
}
- 在调用的时候是可以不用在尖括号中明确表示哪一种类型,编译器会根据接收类型推断出来
类型变量限定
- 为了限制某些类型不是想要的类型
- 代码示例
class Student{
public static <T extends Comparable> T getName(T...a){
//.......
}
}
- 如果想要制作多个限制,使用
&
来分隔
public static <T extends Comparable & Serializable> T getName(T...a){
//.......
}
泛型代码和虚拟机
类型擦除
- 一个泛型类型,自动提供了一个相应的原始类型
- 原始类型的名字就是删去类型参数后的泛型类型名
- 擦除类型变量,替换为限定类型
例如,
T
是一个无限定的变量,就会直接用Object
替换
翻译泛型表达式
- 调用泛型方法,如果擦除返回类型,编译器插入强制类型转换
- 存取一个泛型属性也会插入强制类型转换
Java泛型转换
- 虚拟机中没有泛型,只有普通的类和方法
- 所有的类型参数都有它们的限定类型替换
- 桥方法会合成来保持多态
- 为保持类型安全性,必要时插入强制类型转化
约束和局限性
- 不能用基本类型实例化类型参数
- 运行时类型查询只适用于原始类型
- 同样
getClass
方法总是返回原始类型
- 同样
- 不能创建参数类型的数组
- 可以声明通配类型的数组,然后进行类型转换,但是是不安全的
- 只能使用
ArrayList
Varargs
警告- 不能实例化类型变量
- 最好的解决方法是让调用者提供一个构造器表达式
Class
类本身就是一个泛型类
- 不能构造泛型数组
- 泛型类的静态上下文中类型变量无效
- 不能抛出或捕获泛型类的实例,甚至泛型类扩展
Throwable
都是不合法的 - 可以消除对受查异常的检查
Java
异常处理的基本原则之一是:必须为所有受查异常提供一个处理器,但是可以利用泛型消除这个限制
- 注意擦除后的冲突
- 想要支持擦除的转换,就需要强行限制一个类或类型变量不能同时成为两个接口类型的子类
通配符
- 通配符可以用来作为并不知道准确类型,但是可以设定那一类型的子类或者那一类型是它的父类
- 代码示例
public static void printStr(People<? extends Student> p){
}
public static void printStr(People<? super Student> p){
}
- 带有父类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix