面试核心思路: 先给定义,再讲原理(核心重点),最后谈应用场景。

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. 泛型的使用方式

主要有三种使用场景:

  1. 泛型类: 在类名后声明。
    • public class Box<T> { ... }
  2. 泛型接口: 在接口名后声明。
    • public interface Generator<T> { ... }
  3. 泛型方法:返回值之前声明。
    • 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 (下界)