JAVA泛型用法
原理
泛型的业务价值
- 消除冗余的类型转换
- 代码复用与通用性
什么是类型擦除,以及类型擦除带来的影响
- 无法在运行时获取泛型类型信息
- 不能使用基本数据类型作为泛型类型参数:因为类型擦除后泛型类型参数会被替换为 Object 或边界类型,而基本数据类型不能直接转换为 Object,所以只能使用基本数据类型的包装类作为泛型类型参数。例如,不能使用 List
,而要使用 List 。 - 泛型数组的创建受限:不能直接创建泛型数组,如 new List
[10] 是不允许的,因为类型擦除会导致数组元素类型的信息丢失,可能会引发运行时的 ArrayStoreException 异常。但可以创建通配符类型的数组或使用 ArrayList 等集合来替代。
用法
泛型方法定义
定义泛型方法时,需要在方法返回值类型前显式声明泛型参数(如
// 通用的交换数组元素的方法,适用于任何类型
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// 调用时自动适配类型
Integer[] ints = {1, 2, 3};
swap(ints, 0, 1); // 正确
String[] strs = {"a", "b"};
swap(strs, 0, 1); // 正确
例子2
// 这里需要 T 同时用于参数和返回值,因此必须声明 <T>
public static <T> T getFirstElement(List<T> list) {
return list.get(0);
}
以下不是泛型方法,通配符(如 ? extends Fruit)是一种 “简化的泛型表示”,它直接在方法参数中限定了泛型的范围(这里表示 “任何继承自 Fruit 的类型”),但不引入具体的类型变量(如 T)。
public static void eat(List<? extends Fruit> list) {
for (Fruit fruit : list) {
fruit.eat();
}
}
泛型通配符
- ?:集合只能读,不能写,读到的类型是 Object
- ? extends X:集合只能读,不能写,读到的类型是 X
- ? super X:可以写,写的类型是 X 或 X 的子类型
上界通配符(? extends T)
用法:List<? extends Fruit> list 可以处于子类的泛型集合。比如把 List
public static void eat(List<? extends Fruit> list) {
for (Fruit fruit : list) {
fruit.eat();
}
}
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
apples.add(new Apple());
eat(apples); // 可以传入 Apple 列表
}
但是丢失了添加功能
以下代码编译是不通过的。
List<? extends Apple> apples1 = new ArrayList<>();
apples1.add(new RedApple());
下界通配符
使用 ? super T 来定义,其中 T 是一个具体的类型。它表示泛型类型可以是 T 本身,或者是 T 的任何父类型。
? super T 适合 “写操作”(添加 T 及其子类),但不适合 “读操作”(无法安全转型为 T)。你的代码中遍历并转型为 Apple 的操作,编译器会直接报错。
List<? super Apple> apples1 = new ArrayList<>();
apples1.add(new RedApple());
//以下报错
for(Apple a:apples1){
System.out.println(a.toString());
}
//正确的写法
for(Object a:apples1){
System.out.println(a.toString());
}

浙公网安备 33010602011771号