Skip to content
第 28 / 250 章后端⏱ 10 分钟阅读

第 28 章:泛型深入

学习目标

  • 理解泛型的作用
  • 掌握泛型类、泛型方法
  • 理解类型擦除和通配符

一、为什么需要泛型?

java
// ❌ 没有泛型:每次都要强转,编译期不检查
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);    // 必须强转
list.add(123);                      // ❌ 可以混入 Integer

// ✅ 有泛型:编译期检查
List<String> list = new ArrayList<>();
list.add("hello");
// list.add(123);                   // ❌ 编译报错
String s = list.get(0);             // 自动推断,无需强转

二、泛型类

java
public class Box<T> {            // ① 类型参数 T
    private T content;            // ② 通用类型字段

    public void put(T item) {
        this.content = item;
    }

    public T get() {              // ③ 返回通用类型
        return content;
    }
}

Box<String> stringBox = new Box<>();
stringBox.put("hello");
String s = stringBox.get();

Box<Integer> intBox = new Box<>();
intBox.put(123);
Integer i = intBox.get();

多类型参数

java
public class Pair<K, V> {
    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    // getter, setter, toString
}

Pair<String, Integer> pair = new Pair<>("age", 18);

三、泛型方法

java
public class ArrayUtils {
    // ① 泛型方法:在返回类型前声明 <T>
    public static <T> T getFirst(T[] arr) {
        return arr[0];
    }

    public static <T> void swap(T[] arr, int i, int j) {
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

String[] strs = {"A", "B", "C"};
String first = ArrayUtils.getFirst(strs);
ArrayUtils.swap(strs, 0, 2);

四、通配符

java
List<?> unbounded;               // 任意类型
List<? extends Number> upperBounded;  // Number 及其子类
List<? super Integer> lowerBounded;   // Integer 及其父类

PECS 原则

场景
Producer(只读)<? extends T> 上界通配
Consumer(只写)<? super T> 下界通配
java
// Producer:只能读
public void process(List<? extends Number> list) {
    for (Number n : list) {   // ✅ 读
        System.out.println(n);
    }
    // list.add(1);          // ❌ 不能写
}

// Consumer:只能写
public void fill(List<? super Integer> list) {
    list.add(1);              // ✅ 写
    // Integer i = list.get(0);  // ❌ 不能读
}

五、类型擦除

泛型只在编译期存在,运行时被擦除

java
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();

System.out.println(strList.getClass() == intList.getClass());  // true
System.out.println(strList.getClass());  // class java.util.ArrayList

六、本章小结

要点关键
泛型编译期类型检查,避免强转
泛型类class Box<T>
泛型方法<T> T getFirst(T[])
通配符? / ? extends T / ? super T
类型擦除运行时无泛型信息
PECSProducer 用 extends,Consumer 用 super

动手练习

练习 1:基础题

实现一个 Pair<K, V> 泛型类。

练习 2:进阶题

实现一个泛型方法 max(T[] arr, Comparator<T> cmp),返回数组中的最大值。


下一章第 29 章:异常处理基础

本站基于 VitePress 构建 · 由 Codebook 团队维护