Java 泛型详解:类型参数的力量
泛型(Generics)是 Java 类型系统的重要支柱。
它让代码更安全、更简洁、更通用,是理解现代 Java 编程的必修课。
本文将系统讲解 Java 泛型的定义、使用、通配符、边界与常见陷阱。
一、为什么需要泛型
在 Java 1.5 之前,集合只能存放 Object 类型:
List list = new ArrayList();
list.add("Hello");
list.add(123); // 不安全
String s = (String) list.get(0); // 强制类型转换
缺点:类型不安全、容易出错。
Java 1.5 引入 泛型机制(Generics),允许在定义类或方法时引入“类型参数”。
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123); // 编译错误
String s = list.get(0); // 无需强转
二、泛型的基本语法
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> | 实例化泛型类 |
三、泛型类与泛型接口
泛型类
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; }
}
泛型接口
interface Converter<F, T> {T convert(F from);
}class StringToInteger implements Converter<String, Integer> {public Integer convert(String from) {return Integer.valueOf(from);}
}
四、泛型方法
方法也可以定义自己的类型参数:
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> |
示例:
public static void show(List<? extends Number> list) {for (Number n : list) {System.out.println(n);}
}
| 写入能力 | 读取能力 |
|---|---|
? extends T | ✅ 读安全 ❌ 写 |
? super T | ✅ 写安全 ❌ 读(只能读为 Object) |
六、边界与多重限制
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() 代替。
类型推断:
List<String> list = List.of("A", "B");
var map = Map.of(1, "A", 2, "B"); // Java 10+
八、泛型的好处与限制
| 优点 | 缺点 |
|---|---|
| ✅ 编译期类型安全 | ❌ 运行时类型擦除 |
| ✅ 代码复用性高 | ❌ 无法创建泛型数组 |
| ✅ 无需强转 | ❌ 不能用基本类型 |
九、常见泛型陷阱
❌ 泛型类型不能用于静态上下文:
class Box<T> {// static T value; // 错误!
}
❌ 泛型类型无法用于 instanceof:
if (obj instanceof Box<String>) // 错误:类型擦除导致编译不通过
🔚 总结
| 分类 | 关键语法 | 示例 |
|---|---|---|
| 泛型类 | <T> | class Box<T> |
| 泛型方法 | <T> | static <T> void print(T t) |
| 通配符 | ? extends / ? super | List<? super Integer> |
| 边界 | T extends Number | 限制类型范围 |
