泛型是Java编译期类型约束机制,基于类型擦除实现;List与List编译后均为ArrayList,但编译器拦截非法操作并自动插入安全转型。

泛型是Java在编译期强制执行类型约束的机制,不是运行时特性——它靠“类型擦除”实现,核心作用就一条:List 在编译后和 List 是同一个类(ArrayList),但编译器会拦住你往前者里加 123,也会让你取元素时直接得到 String,不用 (String) list.get(0)。
为什么 new ArrayList() 能防错,而 new ArrayList() 会崩?
因为前者把“只接受 String”这个规则写进了编译检查逻辑里:
- 存的时候:如果写
list.add(42),编译器立刻报错incompatible types,根本不会生成字节码 - 取的时候:
String s = list.get(0)编译通过,JVM 实际执行的是Object o = ...; String s = (String) o—— 这个转型是编译器自动插进去的,安全且不可绕过 - 而
new ArrayList()没有类型声明,编译器放行一切,错误只能留到运行时抛ClassCastException
T、?、? extends Number 到底怎么选?
这不是风格问题,是能不能编译通过的硬边界:
- 用
T(如public class Box):你要封装一个“持有某种类型值”的结构,类型由使用者决定,比如Box或Box - 用
?(通配符):只出现在方法参数中,表示“我接受任意泛型实例”,但你不能往里add任何东西(除了null) - 用
? extends Number:表示“传进来的一定是Number或它的子类(如Integer、Double)”,你可以安全地读出Number,但依然不能add(除非是null) - 用
? super Integer:表示“至少能装下Integer”,你可以add(Integer),但读出来只能当Object用
常见误写:void process(List ≠ void process(List> list)。前者只接受字面量是 List 的实参;后者能接 List、List 等所有泛型 >
List。
立即学习“Java免费学习笔记(深入)”;
哪些操作一定不合法?别试了
这些限制来自类型擦除,不是语法糖不够甜,而是 JVM 根本没保留泛型信息:
-
new T[10]→ 编译错误:T 在运行时不存在,无法确定数组组件类型 -
if (obj instanceof T)→ 编译错误:T 擦除后只剩Object,没法做类型判断 -
T.class→ 编译错误:只有Object.class、String.class这种具体类才有.class -
static List→ 编译错误:静态字段属于类,而cache; T属于实例,二者生命周期不匹配 -
ArrayList→ 编译错误:基本类型不能作泛型实参,必须用ArrayList
最常被忽略的一点:泛型数组虽不能 new T[10],但可以声明 T[] array(字段或返回值),只要不试图在运行时创建它——这个细节在写泛型工具类时极易踩坑。









