Java 泛型(Generics)
泛型是 Java 5 引入的重要特性,它提供了类型安全的集合和类。理解泛型的使用是编写类型安全代码的关键。本章将详细介绍 Java 中的泛型机制。
泛型类与泛型方法
什么是泛型
**泛型(Generics)**允许在定义类、接口和方法时使用类型参数,在使用时指定具体类型。
优势:
- 类型安全:编译时检查类型
- 消除强制转换:不需要手动类型转换
- 代码复用:一个类可以处理多种类型
泛型类
定义泛型类:
// 泛型类定义
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// 使用泛型类
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String item = stringBox.getItem(); // 不需要强制转换
Box<Integer> intBox = new Box<>();
intBox.setItem(100);
Integer number = intBox.getItem(); // 类型安全
多个类型参数
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);
String key = pair.getKey(); // "age"
Integer value = pair.getValue(); // 25
泛型方法
定义泛型方法:
public class Utils {
// 泛型方法
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
// 泛型方法返回类型
public static <T> T getFirst(T[] array) {
if (array.length > 0) {
return array[0];
}
return null;
}
// 多个类型参数
public static <T, U> void printPair(T first, U second) {
System.out.println("First: " + first);
System.out.println("Second: " + second);
}
}
// 使用
String[] strings = {"a", "b", "c"};
Utils.printArray(strings);
Integer[] numbers = {1, 2, 3};
Integer first = Utils.getFirst(numbers);
泛型接口
// 泛型接口
public interface Comparable<T> {
int compareTo(T other);
}
// 实现泛型接口
public class Student implements Comparable<Student> {
private String name;
private int score;
@Override
public int compareTo(Student other) {
return Integer.compare(this.score, other.score);
}
}
类型通配符(? extends / ? super)
无界通配符(?)
? 表示未知类型:
// 可以接受任何类型的 List
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
// 使用
List<String> stringList = Arrays.asList("a", "b");
List<Integer> intList = Arrays.asList(1, 2, 3);
printList(stringList); // ✅ 可以
printList(intList); // ✅ 可以
上界通配符(? extends)
? extends T 表示 T 或其子类型:
// 可以接受 Number 及其子类型的 List
public void processNumbers(List<? extends Number> numbers) {
for (Number num : numbers) {
System.out.println(num.doubleValue());
}
}
// 使用
List<Integer> integers = Arrays.asList(1, 2, 3);
List<Double> doubles = Arrays.asList(1.0, 2.0, 3.0);
processNumbers(integers); // ✅ 可以(Integer extends Number)
processNumbers(doubles); // ✅ 可以(Double extends Number)
// ❌ 错误:不能添加元素(除了 null)
// numbers.add(10); // 编译错误
特点:
- 可以读取元素
- 不能添加元素(除了 null)
- 用于"生产者"场景
下界通配符(? super)
? super T 表示 T 或其父类型:
// 可以接受 Integer 及其父类型的 List
public void addNumbers(List<? super Integer> numbers) {
numbers.add(10); // ✅ 可以添加 Integer
numbers.add(20);
}
// 使用
List<Number> numberList = new ArrayList<>();
List<Object> objectList = new ArrayList<>();
addNumbers(numberList); // ✅ 可以(Number super Integer)
addNumbers(objectList); // ✅ 可以(Object super Integer)
// ❌ 错误:不能读取为具体类型
// Integer num = numbers.get(0); // 编译错误
特点:
- 可以添加元素
- 不能读取为具体类型(只能读取为 Object)
- 用于"消费者"场景
PECS 原则
Producer Extends, Consumer Super:
- Producer(生产者):使用
? extends T - Consumer(消费者):使用
? super T
// 生产者:从集合读取
public void copy(List<? extends Number> source, List<? super Number> dest) {
for (Number num : source) {
dest.add(num); // 从 source 读取,添加到 dest
}
}