Java泛型详解
Java泛型是Java SE 5引入的重要特性,旨在增强类型安全性和代码重用性。以下是对Java泛型的详细讲解,结合核心概念和实际示例:
一、泛型的目的
-
类型安全:编译时检查类型,避免运行时的
ClassCastException
。 -
消除强制转换:减少代码冗余和潜在错误。
-
代码复用:通过参数化类型编写通用代码。
示例(无泛型的问题):
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // 需显式转换,若类型错误则运行时崩溃
二、泛型的基本语法
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("Java");
String value = stringBox.getContent(); // 无需转换
2. 泛型方法
在方法返回类型前声明类型参数:
public <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
调用时自动推断类型:
Integer[] intArray = {1, 2, 3};
printArray(intArray); // 类型推断为Integer
3. 泛型接口
接口定义类型参数:
public interface Comparator<T> {
int compare(T o1, T o2);
}
实现类指定具体类型:
public class StringComparator implements Comparator<String> {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
三、通配符与边界
1. 通配符?
-
上界通配符
<? extends T>
:接受T
及其子类型(生产者)。 -
下界通配符
<? super T>
:接受T
及其父类型(消费者)。
PECS原则(Producer Extends, Consumer Super):
// 生产者:从集合读取数据
void copy(List<? extends Number> src, List<? super Number> dest) {
for (Number num : src) {
dest.add(num);
}
}
2. 无界通配符<?>
表示未知类型,适用于不依赖具体类型的操作:
public void printList(List<?> list) {
for (Object elem : list) {
System.out.println(elem);
}
}
四、类型擦除
Java泛型在编译后擦除类型信息,替换为原生类型(Raw Type)或边界类型(如Object
)。
示例:
// 编译前
List<String> list = new ArrayList<>();
// 编译后(类型擦除)
List list = new ArrayList();
限制:
-
不能创建泛型数组:
new T[]
非法。 -
不能使用
instanceof
检查泛型类型:if (list instanceof List<String>)
错误。 -
不能直接实例化类型参数:需通过反射或工厂模式。
五、泛型与继承
泛型类型在继承关系上是不变的:
-
List<String>
不是List<Object>
的子类。 -
使用通配符实现协变和逆变:
-
协变:
List<? extends Number>
接受List<Integer>
。 -
逆变:
List<? super Integer>
接受List<Number>
。
-
六、实际应用场景
-
集合框架:如
ArrayList<E>
,HashMap<K,V>
。 -
工具类:通用算法(如排序、查找)。
-
回调机制:如
Comparable<T>
,Comparator<T>
。
七、注意事项
-
避免原生类型:如使用
List
而非List<Object>
。 -
优先使用泛型方法:提高灵活性。
-
谨慎使用通配符:明确生产者和消费者角色。
通过掌握泛型,开发者可以编写更安全、灵活且易于维护的代码。理解类型擦除和通配符的使用是深入Java泛型的关键。