前言
面试中会问泛型相关内容,这里简单做一下记录,记录于此,方便自己查看和学习。
正文
Java泛型通过编译期类型检查提升安全性,采用类型擦除实现,配合 PECS 原则 正确使用通配符,是编写健壮、可维护代码的关键。
泛型
泛型(Generics)用于在编译期提供类型检查和类型安全。
主要目的:
- 类型安全:避免 ClassCastException
- 消除强制类型转换
- 提高代码复用性和可读性
Java泛型是伪泛型
- Java泛型只在编译期生效
- 编译后泛型信息会被擦除,替换为:
- 无界泛型 → Object
- 有界泛型 → 边界类型
List<String> list = new ArrayList<>(); // 编译后等价于 List list = new ArrayList();
为什么要用擦除?
为了 向后兼容
上界通配符 <? extends T>
上界通配符是用来“读”
List<? extends Number> list;表示:list 中存放的是 Number 或其子类
特点:
- 可以读取为 Number
- 不能添加元素(除了 null)
原因:
List<Integer> ints = new ArrayList<>(); List<? extends Number> nums = ints; nums.add(1); // ❌ 编译错误
编译器不知道具体是 Integer / Double / Long
Producer(生产者)→ extends
下界通配符 <? super T>
下界通配符是用来“写”
List<? super Integer> list;表示:list 中可以存放 Integer 及其父类
特点:
- 可以添加 Integer
- 读取只能是 Object
Consumer(消费者)→ super
PECS原则
Producer Extends, Consumer Super
生产者Extends,消费者Super
| 场景 | 用法 |
|---|---|
| 只从中取数据 | <? extends T> |
| 只往里写数据 | <? super T> |
| 既要读又要写 | 不用通配符 |
泛型方法 vs 泛型类
- 泛型类
class Box<T> { private T value; }
- 泛型方法
public <T> T getValue(T t) { return t; }
泛型方法不依赖类是否泛型
<T extends Comparable<T>>是什么?
public static <T extends Comparable<T>> T max(T a, T b)含义:
- T 必须是 Comparable 的实现类
- 用于排序、比较
为什么不能 new T()?
T t = new T(); // ❌原因:
- 泛型擦除后变成 Object
- JVM 不知道具体类型
解决方案:
- 传入 Class<T>
T t = clazz.newInstance();为什么不能创建泛型数组?
List<String>[] lists = new List<String>[10]; // ❌原因:
- 数组是 协变的
- 泛型是 不变的
- 会导致运行时类型安全问题
正确方式:
List<?>[] lists = new List<?>[10];泛型与反射的问题
- 运行时泛型信息被擦除
- 反射无法直接获取泛型类型
- 可通过 Type/ ParameterizedType间接获取
ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
参考文章
暂无评论...
