详细介绍:【从零开始java学习|第二十三篇】泛型体系与通配符

泛型是 Java 集合框架的核心特性之一,它通过参数化类型实现代码复用与类型安全。以下从泛型类、泛型方法、泛型接口、泛型通配符四个维度展开,并结合集合的继承关系说明其应用。

一、泛型类:集合的 “容器模板”

定义与语法

泛型类是在类定义时引入类型参数(如 <T>),使类的成员(变量、方法)可操作任意类型。集合框架中,ArrayList<E>HashMap<K,V> 等均为泛型类。

// 自定义泛型类:MyList,模拟ArrayList的简化版
class MyList {
    private Object[] elements;
    private int size;
    public MyList() {
        elements = new Object[10];
    }
    // 泛型方法:添加元素(T类型)
    public void add(T item) {
        elements[size++] = item;
    }
    // 泛型方法:获取元素(返回T类型)
    public T get(int index) {
        return (T) elements[index];
    }
}

集合中的应用

  • ArrayList<E>:通过泛型类实现 “动态数组”,元素类型由<E>指定,避免装箱拆箱开销。
  • HashMap<K,V>:键值对的泛型类,<K>为键类型,<V>为值类型,保证键值对的类型安全。

二、泛型方法:集合工具的 “通用逻辑”

定义与语法

泛型方法是在方法返回值前声明类型参数(如 <T>),使其独立于类的泛型参数。集合工具类Collections中的sortbinarySearch等均为泛型方法。

// 自定义泛型方法:打印任意类型数组
public class CollectionUtils {
    public static  void printArray(T[] array) {
        for (T item : array) {
            System.out.print(item + " ");
        }
        System.out.println();
    }
}

泛型不具备继承性

泛型类型之间不存在继承关系,即使两个类存在继承关系,使用它们作为泛型参数的泛型类型之间也不会自动具有继承关系。例如,假设有类Animal和它的子类DogArrayList<Dog> 不是 ArrayList<Animal> 的子类。

用代码示例可以更直观地说明:

import java.util.ArrayList;
class Animal {}
class Dog extends Animal {}
public class GenericInheritanceTest {
    public static void main(String[] args) {
        // 编译错误,因为ArrayList不是ArrayList的子类
        // ArrayList animalList = new ArrayList();
    }
}

之所以会出现编译错误,是因为泛型类型的设计目的是提供类型安全。如果允许ArrayList<Dog> 是 ArrayList<Animal> 的子类,那么当从ArrayList<Animal>中获取元素时,编译器无法保证获取到的一定是Animal,可能会导致运行时的类型转换异常。比如:

import java.util.ArrayList;
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class GenericInheritanceError {
    public static void main(String[] args) {
        ArrayList dogList = new ArrayList<>();
        dogList.add(new Dog());
        // 假设允许这样的赋值
        ArrayList animalList = dogList;
        animalList.add(new Cat()); // 这里编译时不会报错
        Dog dog = dogList.get(1); // 运行时会抛出ClassCastException,因为索引1处是Cat对象
    }
}

数据具备继承性

虽然泛型类型本身不具备继承性,但存储在泛型集合中的数据是具备继承性的。当定义一个泛型集合,比如ArrayList<Animal> 时,由于DogCat 等类继承自Animal,所以可以将DogCat 等Animal子类的对象添加到ArrayList<Animal> 中。

示例代码如下:

import java.util.ArrayList;
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class DataInheritanceTest {
    public static void main(String[] args) {
        ArrayList animalList = new ArrayList<>();
        animalList.add(new Dog()); // 可以添加Animal的子类对象
        animalList.add(new Cat());
        for (Animal animal : animalList) {
            // 可以按照Animal类型进行处理,也可以根据实际类型进行类型转换后处理
            System.out.println(animal.getClass().getSimpleName());
        }
    }
}

这是因为 Java 的继承机制允许子类对象替代父类对象出现在需要父类对象的地方,也就是常说的里氏替换原则。在泛型集合中,只要集合声明的泛型类型是数据类型的父类,那么就可以将数据类型(子类)的对象添加进去,并且在遍历处理这些对象时,可以按照父类的方式统一处理,也可以根据实际的子类类型进行针对性处理。

集合中的应用

  • Collections.sort(List<T>):通过泛型方法实现对任意List的排序,类型由<T>自动推断。
  • Stream<T> map(Function<T, R>):Stream API 的泛型方法,支持链式操作中的类型转换。

三、泛型接口:集合的 “行为契约”

定义与语法

泛型接口是在接口定义时引入类型参数(如 <E>),实现类需指定具体类型或继续使用泛型。集合框架中,List<E>Set<E>Map<K,V> 均为泛型接口。

// 自定义泛型接口:表示“可迭代”的集合
interface Iterable {
    Iterator iterator();
}
// 实现类:ArrayList实现Iterable
class ArrayList implements Iterable {
    @Override
    public Iterator iterator() {
        return new ArrayListIterator();
    }
    private class ArrayListIterator implements Iterator {
        // 迭代逻辑...
    }
}

集合中的应用

  • List<E>:定义 “有序集合” 的契约,子类(如ArrayListLinkedList)需实现其方法。
  • Comparable<T>:泛型接口,用于对象排序(如Integer实现Comparable<Integer>)。

四、泛型通配符:处理集合的 “继承关系”

泛型本身不支持协变(子类型自动转换),需通过通配符(?? extends T? super T)解决集合的继承兼容问题。

1. 无界通配符 ?

表示 “任意类型”,用于集合仅需操作Object方法(如toString()equals())的场景。

// 打印任意类型的集合
public static void printCollection(Collection coll) {
    for (Object item : coll) {
        System.out.println(item);
    }
}

集合中的应用

  • 通用工具方法(如打印任意ListSet)。

2. 上限通配符 ? extends T

表示 “TT的子类”,遵循PECS 原则(Producer Extends)—— 仅用于 “读取” 数据(生产者)。

// 计算数值集合的总和(T必须是Number的子类)
public static double sum(Collection nums) {
    double total = 0;
    for (Number num : nums) {
        total += num.doubleValue();
    }
    return total;
}

集合中的应用

  • List<? extends Number> 可接收List<Integer>List<Double>等,实现数值类型的统一处理。

3. 下限通配符 ? super T

表示 “TT的父类”,遵循PECS 原则(Consumer Super)—— 仅用于 “写入” 数据(消费者)。

// 向集合中添加整数(集合类型必须是Integer或其父类)
public static void addIntegers(List list) {
    list.add(10);
    list.add(20);
}

集合中的应用

  • List<? super Integer> 可接收List<Integer>List<Number>List<Object>,实现数据的向上兼容存储。

4. 泛型继承关系的处理

泛型不支持直接协变(如List<Integer>不是List<Number>的子类),但通过通配符可间接建立关系:

// 错误:泛型不支持直接协变
// List nums = new ArrayList();
// 正确:通过上限通配符建立关系
List intList = new ArrayList();
List numList = intList; // 合法,因为Integer是Number的子类

五、总结:泛型在集合中的核心价值

  1. 类型安全:编译期检查集合元素类型,避免ClassCastException
  2. 代码复用:泛型类 / 方法 / 接口实现 “一次编写,多类型适用”(如ArrayList可存储任意类型)。
  3. 灵活兼容:通配符(? extends T? super T)解决泛型与继承的兼容问题,适配复杂场景。

如果我的内容对你有帮助,请点赞,评论,收藏。接下来我将继续更新相关内容!

posted @ 2025-11-12 13:09  clnchanpin  阅读(40)  评论(0)    收藏  举报