Java泛型 #
一、泛型概述 #
1.1 什么是泛型 #
泛型是Java 5引入的特性,允许在定义类、接口、方法时使用类型参数。
1.2 泛型的好处 #
- 类型安全
- 消除类型转换
- 提高代码复用
1.3 泛型示例 #
java
// 没有泛型
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // 需要类型转换
// 使用泛型
List<String> list2 = new ArrayList<>();
list2.add("Hello");
String s2 = list2.get(0); // 无需类型转换
二、泛型类 #
2.1 定义泛型类 #
java
public class Box<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
// 使用
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get();
Box<Integer> intBox = new Box<>();
intBox.set(100);
Integer num = intBox.get();
2.2 多个类型参数 #
java
public 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; }
}
// 使用
Pair<String, Integer> pair = new Pair<>("age", 25);
三、泛型接口 #
3.1 定义泛型接口 #
java
public interface Generator<T> {
T generate();
}
// 实现方式1:指定具体类型
public class StringGenerator implements Generator<String> {
@Override
public String generate() {
return "Hello";
}
}
// 实现方式2:保留泛型
public class GenericGenerator<T> implements Generator<T> {
@Override
public T generate() {
return null;
}
}
四、泛型方法 #
4.1 定义泛型方法 #
java
public class Utils {
// 泛型方法
public static <T> void print(T value) {
System.out.println(value);
}
// 多个类型参数
public static <K, V> void printPair(K key, V value) {
System.out.println(key + " = " + value);
}
// 返回泛型
public static <T> T getFirst(List<T> list) {
return list.isEmpty() ? null : list.get(0);
}
}
// 使用
Utils.print("Hello");
Utils.print(100);
Utils.printPair("name", "张三");
4.2 泛型方法与泛型类 #
java
public class Box<T> {
private T value;
// 泛型类的类型参数T
public void set(T value) {
this.value = value;
}
// 泛型方法,使用新的类型参数E
public <E> void print(E element) {
System.out.println(element);
}
}
五、类型通配符 #
5.1 无界通配符 #
java
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
// list.add("test"); // 错误:不能添加元素
}
5.2 上界通配符 #
java
// 接受Number及其子类
public double sum(List<? extends Number> list) {
double total = 0;
for (Number num : list) {
total += num.doubleValue();
}
return total;
}
// 使用
List<Integer> ints = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.5, 2.5, 3.5);
System.out.println(sum(ints));
System.out.println(sum(doubles));
5.3 下界通配符 #
java
// 接受Integer及其父类
public void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
list.add(3);
}
// 使用
List<Number> numbers = new ArrayList<>();
addNumbers(numbers);
List<Object> objects = new ArrayList<>();
addNumbers(objects);
5.4 PECS原则 #
- Producer Extends:从集合读取(生产)时使用
? extends T - Consumer Super:向集合写入(消费)时使用
? super T
java
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (T item : src) {
dest.add(item);
}
}
六、类型擦除 #
6.1 擦除规则 #
java
// 编译前
public class Box<T> {
private T value;
}
// 编译后(类型擦除)
public class Box {
private Object value;
}
6.2 桥方法 #
java
public class StringBox extends Box<String> {
@Override
public void set(String value) {
// ...
}
// 编译器生成的桥方法
public void set(Object value) {
set((String) value);
}
}
七、泛型限制 #
7.1 不能使用基本类型 #
java
// 错误
// List<int> list = new ArrayList<>();
// 正确:使用包装类
List<Integer> list = new ArrayList<>();
7.2 不能实例化类型参数 #
java
public class Box<T> {
// 错误
// T value = new T();
// 正确:使用反射
public T create(Class<T> clazz) throws Exception {
return clazz.getDeclaredConstructor().newInstance();
}
}
7.3 不能创建泛型数组 #
java
// 错误
// T[] array = new T[10];
// 正确
@SuppressWarnings("unchecked")
T[] array = (T[]) new Object[10];
八、总结 #
| 概念 | 说明 |
|---|---|
| 泛型类 | class Box<T> |
| 泛型接口 | interface Generator<T> |
| 泛型方法 | <T> void method(T t) |
| 上界通配符 | ? extends T |
| 下界通配符 | ? super T |
泛型要点:
- 泛型提供编译时类型检查
- 使用PECS原则选择通配符
- 泛型在运行时被擦除
- 不能使用基本类型作为类型参数
最后更新:2026-03-26