面试核心思路: 先给定义,再讲原理(核心重点),最后谈应用场景。
1. 什么是泛型?(Definition)
一句话总结: 泛型本质是参数化类型。 它允许我们在创建类、接口或方法时,把具体的“类型”当作一个参数传进去。
- 目的: 为了让代码更通用,并且在编译阶段就能检查类型安全,避免强制转换的麻烦。
- 通俗例子: 就像一个贴了标签的箱子。
- 无泛型: 箱子没标签,什么都能往里塞(Integer, String),但取出来时容易弄错(ClassCastException)。
- 有泛型: 贴了
<String>标签,编译器会盯着你,只准你放 String,取出来也保证是 String。
2. 核心原理:类型擦除 (Type Erasure) —— 面试必考
这是泛型的“杀手锏”问题。Java 的泛型是伪泛型。
-
机制: 泛型信息只存在于代码编译阶段。一旦编译成字节码(.class文件),泛型信息就会被擦除。
-
擦除后变成什么?
- 所有的泛型参数
<T>都会被替换为它的上界(Bound)。 - 如果没有指定上界(如
<T>),则替换为Object。 - 如果指定了上界(如
<T extends String>),则替换为String。
- 所有的泛型参数
-
证据:
List<String> list1 = new ArrayList<>(); List<Integer> list2 = new ArrayList<>(); // 输出为 true,因为运行时它们都是 ArrayList.class System.out.println(list1.getClass() == list2.getClass());
3. 泛型的使用方式
主要有三种使用场景:
- 泛型类: 在类名后声明。
public class Box<T> { ... }
- 泛型接口: 在接口名后声明。
public interface Generator<T> { ... }
- 泛型方法: 在返回值之前声明。
public <E> void printArray(E[] inputArray) { ... }- 注意: 静态方法无法访问类上定义的泛型(因为静态加载早于对象创建),所以静态方法如果要用泛型,必须自己声明成泛型方法。
4. 通配符 (Wildcards)
为了解决泛型的继承问题(因为 List<Father> 不能接受 List<Son>),Java 引入了通配符:
<?>无界通配符: 什么都能接,但通常只能读(当 Object 读),不能写(除了 null)。<? extends T>上界通配符: 只能接 T 及其子类。- 特点: 适合读取数据(Producer)。
<? super T>下界通配符: 只能接 T 及其父类。- 特点: 适合写入数据(Consumer)。
- PECS 原则 (Producer Extends, Consumer Super):
- 如果你要从集合中频繁读取数据,用
extends。 - 如果你要往集合中频繁插入数据,用
super。
- 如果你要从集合中频繁读取数据,用
总结表格
| 特性 | 说明 |
|---|---|
| 本质 | 参数化类型 (Parameterized Type) |
| 核心优势 | 编译时类型检查、无需强制转换 |
| 底层实现 | 类型擦除 (Type Erasure),运行时变为 Object 或上界 |
| PECS原则 | 读多用 extends (上界),写多用 super (下界) |