第一部分:通配符基础
理解泛型通配符的核心概念和使用场景
学习目标
掌握三种通配符的基本语法和应用场景
Java泛型通配符类型
无界通配符
- 表示未知类型的集合
- 只允许读取为Object类型
- 不能添加除null外的任何元素
- 最安全的读取方式
上界通配符
- 表示Number或其子类的集合
- 安全读取为Number类型
- 不能添加除null外的任何元素
- 适用于只读操作
下界通配符
- 表示Integer或其父类的集合
- 可以添加Integer及其子类对象
- 读取只能得到Object类型
- 适用于只写操作
为什么需要通配符?
Java泛型系统在实现泛型类/方法时会出现继承关系问题:
关键概念:泛型类型在Java中是不变的(Invariant),通配符提供了协变和逆变的解决方案
基本使用示例
演示三种通配符的使用场景:
第二部分:上界通配符(? extends T)
学习如何安全地读取包含子类对象的集合
学习目标
掌握上界通配符的使用场景和限制
上界通配符的特点
- 读取安全:可以安全地读取元素为T类型
- 写入限制:除null外不能添加任何元素
- 用途:只读操作(生产者)
- 例子:
List<? extends Number>
可以是List<Integer>, List<Double>等
使用场景
- 集合元素作为输入(生产者)
- 遍历和读取集合内容
- 集合内容不关心具体子类型
- 计算、统计等操作
第三部分:下界通配符(? super T)
学习如何安全地向父类型集合添加元素
学习目标
掌握下界通配符的使用场景和限制
下界通配符的特点
- 写入安全:可以添加T及其子类对象
- 读取限制:只能读取为Object类型
- 用途:写入操作(消费者)
- 例子:
List<? super Integer>
可以是List<Integer>, List<Number>等
使用场景
- 集合作为输出(消费者)
- 向集合中添加元素
- 集合类型不关心具体元素类型
- 收集器、消费者等模式
第四部分:PECS原则
掌握使用通配符的核心设计原则
学习目标
理解和应用Producer-Extends, Consumer-Super原则
PECS原则解释
在使用泛型通配符时遵循的核心原则:
- 如果你需要一个提供数据的生产者(Producer),使用
<? extends T>
- 如果你需要一个消费数据的消费者(Consumer),使用
<? super T>
- 如果你两者都需要,使用精确类型
<T>
PECS原则应用
在Java API设计中广泛使用的原则:
实践案例:合并集合
使用PECS原则设计合并集合的方法:
第五部分:类型擦除原理
揭秘Java泛型在编译时的转换机制
学习目标
理解Java泛型在编译时如何处理类型信息
类型擦除机制
Java泛型通过类型擦除实现,在编译阶段完成以下转换:
- 将泛型类型参数替换为边界类型(无边界则为Object)
- 在必要位置插入类型转换
- 生成桥接方法以保持多态性
源代码 | 编译后(类型擦除后) | 说明 |
---|---|---|
List<String> list = new ArrayList<>(); | List list = new ArrayList(); | 类型参数被擦除 |
list.add("Hello"); | list.add("Hello"); | 方法调用无需转换 |
String s = list.get(0); | String s = (String) list.get(0); | 插入强制类型转换 |
T getData() { ... } | Object getData() { ... } | 方法返回类型被擦除 |
边界替换
当使用边界时,编译器会使用边界类型替换类型参数:
桥接方法
当泛型方法与继承发生冲突时,编译器生成桥接方法:
重要:桥接方法由编译器自动生成,确保类型安全的继承机制
第六部分:类型擦除的影响
理解Java泛型在运行时的限制
学习目标
掌握类型擦除带来的限制以及解决方案
类型擦除的主要限制
解决方案与最佳实践
运行时类型信息技巧
通过反射获取泛型信息:
注意:此方法只适用于编译时已知具体类型的情况
第七部分:常见错误与陷阱
避免泛型编程中的常见错误
错误1:混淆通配符类型
解决方案:使用精确类型或下界通配符进行写入操作
错误2:忽略类型擦除影响
解决方案:使用类型反射或传递Class对象解决运行时类型问题
错误3:误用原始类型
解决方案:避免使用原始类型,确保所有集合都使用泛型声明
错误4:过度使用无界通配符
解决方案:合理使用上界或下界通配符,或设计为泛型方法
第八部分:动手练习
通过编码练习巩固泛型知识
练习1:通用转换器
创建一个泛型类 Converter<T, R>
,实现不同类型转换的功能:
练习2:安全过滤器
创建一个泛型方法,过滤集合中满足特定条件的元素:
练习3:列表转换器
创建一个泛型方法将List<List<?>>
转换为List<?>
:
练习4:类型安全的交换
创建一个泛型方法交换数组中两个元素的位置: