泛型(Generics)是 Java 类型系统的重要支柱。
它让代码更安全、更简洁、更通用,是理解现代 Java 编程的必修课。
本文将系统讲解 Java 泛型的定义、使用、通配符、边界与常见陷阱。
一、为什么需要泛型
在 Java 1.5 之前,集合只能存放 Object 类型:
java
List list = new ArrayList();
list.add("Hello");
list.add(123); // 不安全
String s = (String) list.get(0); // 强制类型转换
缺点:类型不安全、容易出错。
Java 1.5 引入 泛型机制(Generics),允许在定义类或方法时引入"类型参数"。
java
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123); // 编译错误
String s = list.get(0); // 无需强转
二、泛型的基本语法
java
class Box<T> { // 定义泛型类
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Box<Integer> box = new Box<>();
box.set(100);
Integer data = box.get();
| 关键点 | 说明 |
|---|---|
<T> |
声明类型参数(Type Parameter) |
T |
类型变量,可代表任意引用类型 |
Box<Integer> |
实例化泛型类 |
三、泛型类与泛型接口
泛型类
java
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) { this.key = key; this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
泛型接口
java
interface Converter<F, T> {
T convert(F from);
}
class StringToInteger implements Converter<String, Integer> {
public Integer convert(String from) {
return Integer.valueOf(from);
}
}
四、泛型方法
方法也可以定义自己的类型参数:
java
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
String[] arr = {"A", "B", "C"};
printArray(arr); // 自动推断 T = String
⚡ 泛型方法的类型参数与类的泛型参数独立存在。
五、通配符:? 的三种形态
通配符 ? 表示未知类型,常用于方法参数中。
| 通配符 | 含义 | 示例 |
|---|---|---|
? |
任意类型 | List<?> list |
? extends T |
T 或其子类(上界通配符) | List<? extends Number> |
? super T |
T 或其父类(下界通配符) | List<? super Integer> |
示例:
java
public static void show(List<? extends Number> list) {
for (Number n : list) {
System.out.println(n);
}
}
| 写入能力 | 读取能力 |
|---|---|
? extends T |
✅ 读安全 ❌ 写 |
? super T |
✅ 写安全 ❌ 读(只能读为 Object) |
六、边界与多重限制
java
class Calculator<T extends Number & Comparable<T>> {
public boolean isGreater(T a, T b) {
return a.compareTo(b) > 0;
}
}
✅ 可指定多个上界,必须先是类后是接口。
七、泛型数组与类型推断
- ❌ 泛型数组不能直接创建:new T[10](类型擦除原因)
- ✅ 可使用 List 或 Array.newInstance() 代替。
类型推断:
java
List<String> list = List.of("A", "B");
var map = Map.of(1, "A", 2, "B"); // Java 10+
八、泛型的好处与限制
| 优点 | 缺点 |
|---|---|
| ✅ 编译期类型安全 | ❌ 运行时类型擦除 |
| ✅ 代码复用性高 | ❌ 无法创建泛型数组 |
| ✅ 无需强转 | ❌ 不能用基本类型 |
九、常见泛型陷阱
❌ 泛型类型不能用于静态上下文:
java
class Box<T> {
// static T value; // 错误!
}
❌ 泛型类型无法用于 instanceof:
java
if (obj instanceof Box<String>) // 错误:类型擦除导致编译不通过
🔚 总结
| 分类 | 关键语法 | 示例 |
|---|---|---|
| 泛型类 | <T> |
class Box<T> |
| 泛型方法 | <T> |
static <T> void print(T t) |
| 通配符 | ? extends / ? super |
List<? super Integer> |
| 边界 | T extends Number |
限制类型范围 |