题目
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为Integer2. 通配符使用
通配符(?)用于增强泛型的灵活性:
- 无界通配符(<?>):
// 接受任何泛型类型的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(); }