侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Java泛型基础 - 理解泛型方法和通配符

2025-12-13 / 0 评论 / 4 阅读

题目

Java泛型基础 - 理解泛型方法和通配符

信息

  • 类型:问答
  • 难度:⭐

考点

泛型方法定义,通配符使用,类型擦除

快速回答

快速回答要点:

  • 泛型方法在方法返回类型前声明类型参数(如 <T>)
  • 通配符? 用于未知类型:
    • <?> 表示任意类型(无界)
    • <? extends T> 表示T或其子类(上界)
    • <? super T> 表示T或其父类(下界)
  • 类型擦除:编译后泛型类型会被替换为Object或边界类型
## 解析

1. 核心概念

泛型方法:在方法返回类型前声明类型参数,使方法能独立于类处理不同类型。例如:

// 泛型方法定义
public <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.print(element + " ");
    }
}

// 调用示例
String[] strArr = {"A", "B"};
Integer[] intArr = {1, 2};
printArray(strArr); // 自动推断T为String
printArray(intArr); // 自动推断T为Integer

2. 通配符使用

通配符(?)用于增强泛型的灵活性:

  • 无界通配符(<?>)
    // 接受任何泛型类型的List
    public void processList(List<?> list) {
        for (Object obj : list) {
            System.out.println(obj);
        }
    }
  • 上界通配符(<? extends T>)
    // 接受Number及其子类(如Integer/Double)的List
    public double sum(List<? extends Number> list) {
        double total = 0;
        for (Number num : list) {
            total += num.doubleValue();
        }
        return total;
    }
  • 下界通配符(<? super T>)
    // 接受Integer及其父类(如Number/Object)的List
    public void addNumbers(List<? super Integer> list) {
        list.add(10); // 安全写入
        list.add(20);
    }

3. 类型擦除原理

Java泛型在编译后会被擦除:

  • 泛型类型参数会被替换为Object或边界类型(如 <T extends Number> 擦除为Number)
  • 示例:List<String>List<Integer> 编译后都变成 List
  • 导致运行时无法获取泛型具体类型(如 if(list instanceof ArrayList<String>) 无效)

4. 最佳实践与常见错误

最佳实践:

  • 优先使用泛型方法而非强制转换
  • 遵循PECS原则(Producer-Extends, Consumer-Super):
    • 生产者(读取数据)用 <? extends T>
    • 消费者(写入数据)用 <? super T>

常见错误:

  • 错误1:尝试创建泛型数组
    // 编译错误! T[] arr = new T[10];
  • 错误2:在静态上下文中使用类的类型参数
    class Box<T> { // 错误!静态方法不能访问T static T getStatic() { return null; } }
  • 错误3:混淆泛型继承关系
    List<Number> list = new ArrayList<Integer>(); // 编译错误!

5. 扩展知识

  • 桥接方法(Bridge Method):编译器在类型擦除后自动生成的方法,用于保持多态性
  • 泛型与重载void method(List<String> list)void method(List<Integer> list) 不能重载(擦除后签名相同)
  • 类型令牌(Type Token):通过 Class<T> 在运行时保留类型信息,如:
    public <T> T create(Class<T> type) {
        return type.newInstance();
    }