JAVA泛型用法

原理

泛型的业务价值

  • 消除冗余的类型转换
  • 代码复用与通用性

什么是类型擦除,以及类型擦除带来的影响

  • 无法在运行时获取泛型类型信息
  • 不能使用基本数据类型作为泛型类型参数:因为类型擦除后泛型类型参数会被替换为 Object 或边界类型,而基本数据类型不能直接转换为 Object,所以只能使用基本数据类型的包装类作为泛型类型参数。例如,不能使用 List,而要使用 List
  • 泛型数组的创建受限:不能直接创建泛型数组,如 new List[10] 是不允许的,因为类型擦除会导致数组元素类型的信息丢失,可能会引发运行时的 ArrayStoreException 异常。但可以创建通配符类型的数组或使用 ArrayList 等集合来替代。

用法

泛型方法定义

定义泛型方法时,需要在方法返回值类型前显式声明泛型参数(如 ),否则编译器无法识别 T 是泛型类型参数,会将其视为一个未定义的普通类,从而报错(提示 “找不到符号 T”)。

// 通用的交换数组元素的方法,适用于任何类型
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 apples = new ArrayList<>();传给 List<? extends Fruit> 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());
        }
posted @ 2025-02-24 19:20  向着朝阳  阅读(44)  评论(0)    收藏  举报