1. 泛型的本质与设计哲学
Java泛型是2004年JDK 5.0引入的核心特性,它从根本上改变了Java的类型系统。泛型的本质是参数化类型(Parameterized Types),这种设计允许我们在类、接口和方法定义时使用类型参数,在实际使用时再指定具体类型。
1.1 类型参数化的双重含义
在传统方法中,我们熟悉的是值参数化:
java复制public void process(int value) { ... }
这里的value是值的占位符,调用时传入具体数值如process(5)。
泛型则引入了更高维度的参数化——类型参数化:
java复制public class Container<T> { ... }
这里的<T>是类型的占位符,使用时指定具体类型如Container<String>。
关键区别:值参数化决定方法操作的数据内容,类型参数化决定代码操作的数据类型。
1.2 泛型的设计动机
泛型主要解决三个核心问题:
- 类型安全:编译期捕获类型错误,避免运行时的ClassCastException
- 代码复用:一套逻辑可适用于多种类型,减少重复代码
- 表达力增强:API设计能更精确地表达类型约束关系
以集合框架为例,没有泛型时:
java复制List list = new ArrayList();
list.add("hello");
String s = (String)list.get(0); // 需要强制转换
引入泛型后:
java复制List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // 自动类型安全
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 泛型的三种基本形式
2.1 泛型接口的实现策略
泛型接口的实现存在两种范式选择,这对类设计有深远影响。
范式一:具体化实现
java复制interface Repository<T> {
void save(T data);
}
class StringRepository implements Repository<String> {
@Override
public void save(String data) {
// 只能处理String类型
}
}
特点:
- 实现时已确定具体类型
- 类签名不再包含类型参数
- 适用于业务场景明确的场合
范式二:泛型延续
java复制class GenericRepository<T> implements Repository<T> {
@Override
public void save(T data) {
// 保持泛型特性
}
}
特点:
- 实现类继续保留类型参数
- 将类型参数传递给接口
- 适用于需要保持灵活性的基础组件
两种范式的对比维度
| 特性 | 具体化实现 | 泛型延续 |
|---|---|---|
| 类型确定时机 | 编译期 | 运行时 |
| 代码复用性 | 低 | 高 |
| 类型安全性 | 强 | 强 |
| 适用场景 | 终端业务逻辑 | 基础框架组件 |
2.2 泛型类的实现细节
类型擦除机制
Java泛型采用擦除式实现,编译后会移除类型参数信息:
原始代码:
java复制class Box<T> {
T value;
}
擦除后等效代码:
java复制class Box {
Object value;
}
当指定上界时:
java复制class NumberBox<T extends Number> {
T value;
}
擦除为:
java复制class NumberBox {
Number value;
}
重要原则:泛型信息只存在于编译阶段,运行时无法获取类型参数的实际类型。
泛型与基本类型
Java泛型不支持基本类型,这是由擦除机制决定的:
错误示例:
java复制List<int> list = new ArrayList<>(); // 编译错误
正确做法:
java复制List<Integer> list = new ArrayList<>();
2.3 泛型方法的特殊规则
泛型方法语法:
java复制public <T> T merge(T item1, T item2) {
// 方法实现
}
关键特性:
- 类型参数声明在方法修饰符和返回类型之间
- 独立于类的泛型参数(即使类不是泛型类也可以有泛型方法)
- 静态方法必须使用泛型方法形式才能获得泛型能力
典型应用场景:
java复制public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
// 实现集合拷贝
}
}
3. 类型通配符的深层解析
3.1 通配符基础概念
通配符?表示未知类型,它解决的是泛型不变性带来的限制。Java泛型默认具有不变性(invariant),即List<String>与List<Object>没有继承关系。
通配符引入协变和逆变能力:
<? extends T>实现协变(covariant)<? super T>实现逆变(contravariant)
3.2 上界通配符的读写限制
语法:<? extends Number>
示例:
java复制List<? extends Number> numbers = new ArrayList<Double>();
读取特性:
java复制Number n = numbers.get(0); // 安全读取
写入限制:
java复制numbers.add(1.0); // 编译错误
原因:编译器无法确定实际类型是否匹配,唯一允许写入null
