第一部分:泛型基础概念
理解泛型的核心思想和解决的问题,以及它如何提高代码的安全性和重用性
学习目标
理解泛型解决的问题,掌握泛型的基本语法和优势
什么是泛型?
泛型是JDK 5引入的重要特性,允许在定义类、接口和方法时使用类型参数。
泛型的核心价值:
- 类型安全:编译时检查类型错误
- 代码重用:一套代码处理多种数据类型
- 消除强制类型转换
- 更好的代码可读性
泛型解决的问题
在引入泛型之前,Java集合只能存储Object类型,使用时需要强制类型转换:
泛型解决了这些问题,使代码更安全、更简洁。
无泛型的问题
- 运行时的类型转换错误
- 需要大量类型转换代码
- 可读性差,难以理解集合元素类型
- 代码安全性低
使用泛型的优势
- 编译时类型检查
- 消除强制类型转换
- 代码更简洁易读
- 代码重用性更高
- API设计更灵活
第二部分:泛型类与接口
学习如何定义和使用泛型类、泛型接口
学习目标
能够创建自定义泛型类和接口,并理解其实现原理
定义泛型类
在类名后添加类型参数声明(用尖括号 <><>> 包围)
这里 T
是类型参数,可以用任何有效标识符(常用T、E、K、V等)。
使用泛型类
创建泛型类实例时指定具体类型:
注意:从Java 7开始,可以使用"钻石"操作符 <><>> 简化泛型实例化
泛型接口
接口也可以使用泛型,定义方式类似:
第三部分:泛型方法
学习如何定义和使用泛型方法
学习目标
掌握泛型方法的定义和使用,理解类型推断原理
定义泛型方法
泛型方法在方法返回类型前声明类型参数:
第一个方法 swap
是简单的泛型方法,第二个方法 max
使用了类型边界(后面会详细讲解)。
调用泛型方法
Java编译器通常可以自动推断类型参数:
注意:静态方法可以是泛型方法,即使类本身不是泛型类
第四部分:类型边界
学习如何限制泛型类型参数的范围
学习目标
掌握类型边界的使用,理解上界和下界的区别
上界通配符 (extends)
使用 <T extends Type>
限制类型参数必须是特定类型或其子类型
上界通配符示例
多边界类型参数
类型参数可以有多个边界,使用 <T extends A & B & C>
多边界示例
注意:类边界必须放在接口边界之前,且最多只能有一个类边界
第五部分:通配符
学习使用通配符提高API的灵活性
学习目标
掌握通配符的使用场景,理解PECS原则
上界通配符 (?)
使用 <? extends Type>
表示接受Type或其子类型的集合
上界通配符示例
下界通配符 (?)
使用 <? super Type>
表示接受Type或其父类型的集合
下界通配符示例
PECS原则 (Producer-Extends, Consumer-Super)
使用通配符时的最佳实践:
- 当你需要从集合中获取元素(生产者)时,使用
<? extends T>
- 当你需要向集合中添加元素(消费者)时,使用
<? super T>
- 当你既需要获取又需要添加时,使用精确类型
<T>
第六部分:类型擦除
理解Java泛型的实现机制和限制
学习目标
掌握类型擦除原理,理解泛型在运行时的行为
什么是类型擦除?
Java泛型是通过类型擦除(Type Erasure)实现的,编译器在编译时移除所有类型信息:
- 所有类型参数被替换为它们的边界(如无边界则替换为Object)
- 在必要的位置插入类型转换
- 生成桥接方法以保持多态性
类型擦除的影响
由于类型擦除,泛型在运行时有一些限制:
第七部分:常见错误与陷阱
避免泛型编程中的常见错误
错误1:使用原始类型
解决方案:总是使用泛型类型声明集合
错误2:忽略未检查警告
解决方案:修正代码消除警告,而不是忽略或压制
错误3:混淆类泛型和方法泛型
解决方案:静态方法不能使用类泛型参数,应定义为泛型方法
错误4:误用通配符
解决方案:使用下界通配符或精确类型
第八部分:动手练习
通过实践巩固泛型知识
练习1:泛型Pair类
创建一个泛型类 Pair<K, V>
,包含两个字段:key(类型为K)和value(类型为V)
- 实现构造方法接受key和value
- 实现getKey()和getValue()方法
- 实现setKey()和setValue()方法
- 添加一个swap()方法,交换key和value的位置
练习2:统计方法
创建一个泛型方法,计算数组中特定元素出现的次数:
练习3:排序工具
创建一个泛型方法,使用冒泡排序对数组进行排序:
练习4:列表操作
实现以下泛型方法: