一、泛型的基本概念
泛型(Generics)是JDK 5引入的重要特性,它允许在定义类、接口和方法时使用类型参数,将类型检查从运行时提前到编译时。
核心思想
-
参数化类型:将类型作为参数传递
-
类型安全:编译时进行类型检查
-
消除强制类型转换:减少ClassCastException风险
二、泛型的基本语法
1. 泛型类
// T是类型参数
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
// 使用
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String value = stringBox.getContent(); // 无需强制转换
2. 泛型接口
public interface List<T> {
void add(T element);
T get(int index);
}
// 实现
public class ArrayList<T> implements List<T> {
// 实现细节...
}
3. 泛型方法
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
// 使用
Integer[] intArray = {1, 2, 3};
printArray(intArray); // 类型推断
三、泛型的高级特性
1. 类型通配符
-
无界通配符:
<?>
public void processList(List<?> list) { // 可以接受任何类型的List }
-
上界通配符:
<? extends T>
public double sumOfList(List<? extends Number> list) { double sum = 0.0; for (Number num : list) { sum += num.doubleValue(); } return sum; }
-
下界通配符:
<? super T>
public void addNumbers(List<? super Integer> list) { list.add(1); list.add(2); }
2. 类型擦除
Java泛型是通过类型擦除实现的,编译后会去除类型信息:
// 编译前
List<String> list = new ArrayList<>();
// 编译后(类型擦除)
List list = new ArrayList();
3. 泛型与数组
不能创建泛型数组:
// 错误写法
List<String>[] arrayOfLists = new List<String>[10];
// 正确方式
List<?>[] arrayOfLists = new List<?>[10];
四、泛型的应用场景
1. 集合框架
List<String> strings = new ArrayList<>();
Map<Integer, String> map = new HashMap<>();
2. 通用算法实现
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
3. 类型安全的容器
public class Cache<T> {
private T data;
public void store(T data) {
this.data = data;
}
public T retrieve() {
return data;
}
}
4. 工厂模式
public interface Factory<T> {
T create();
}
public class StringFactory implements Factory<String> {
public String create() {
return new String();
}
}
五、泛型的最佳实践
-
尽量使用泛型:提高代码类型安全性和可读性
-
避免原生类型:如使用
List
而不是List<String>
-
优先使用泛型方法:当方法操作不依赖类泛型参数时
-
合理使用通配符:提高API灵活性
-
注意类型擦除的影响:运行时无法获取泛型类型信息
六、常见问题
-
不能使用基本类型:如
List<int>
非法,应使用List<Integer>
-
不能实例化类型参数:
new T()
非法 -
静态成员不能使用类泛型参数:因为静态成员属于类而非实例
泛型极大地提高了Java程序的类型安全性和代码重用性,是现代Java开发中不可或缺的特性。