泛型将类型检查从运行时提前到编译期,避免ClassCastException并消除冗余强制转换;采用类型擦除实现向后兼容,但导致无法new T()、instanceof检测泛型参数等限制;边界机制(extends/super)约束操作范围。

泛型解决了类型安全缺失导致的运行时 ClassCastException
没有泛型时,ArrayList 存什么取什么都要靠 Object 中转,编译期无法检查类型匹配。比如往 ArrayList 里加了 String,又误取成 Integer,错误只能在运行时暴露——这违背了“越早发现错误越好”的工程原则。
- 泛型把类型检查从运行时提前到编译期,
ArrayList不允许add(123),编译直接报错 - 避免了大量冗余的强制类型转换,如
(String) list.get(0)在泛型中变成直接的list.get(0) - 擦除后生成的字节码仍保持向后兼容,老代码无需重写就能和新泛型代码共存
泛型不是语法糖,而是编译器驱动的类型约束机制
Java 泛型采用类型擦除(type erasure),意味着 ArrayList 和 ArrayList 在运行时都是 ArrayList,没有独立的泛型类实例。这不是缺陷,而是设计权衡:兼容 JVM 旧版本、避免泛型爆炸、简化反射和序列化逻辑。
- 不能用
new T()或T.class,因为运行时 T 已被擦除为Object -
instanceof无法检测泛型参数,if (obj instanceof ArrayList编译不通过) - 静态方法不能直接访问所在类的类型参数,必须显式声明自己的类型变量,如
public staticT getFirst(List list)
泛型边界(extends / super)解决“能操作什么”和“能接受什么”的问题
无界泛型()太宽泛,实际使用中常需限定范围。上界 extends 表示“能用哪些方法”,下界 super 表示“能塞进哪些数据”。
-
List extends Number>:可读出Number及其子类,但不能add任何具体类型(除了null),因为编译器不知道实际是Integer还是Double -
List super Integer>:可安全add(Integer),但读出只能当Object用,因为底层可能是List或List - PECS 原则(Producer Extends, Consumer Super)是理解边界的实用口诀,但别死记——看你是从集合取值(producer)还是往里放值(consumer)
泛型与原始类型混用会触发 unchecked 警告,不是小事
调用遗留 API 或反射场景中,容易写出 ArrayList list = new ArrayList 这类原始类型赋值。编译器会发出 unchecked assignment 警告,这不是可忽略的噪音,而是潜在的类型安全缺口。
立即学习“Java免费学习笔记(深入)”;
- 一旦发生 unchecked 操作,后续对该容器的所有泛型操作都可能绕过类型检查
-
@SuppressWarnings("unchecked")必须加在最小作用域,且旁边注释说明为什么安全,例如“已确认传入元素全为 String” - 优先用
Arrays.asList()、Collections.singletonList()等泛型友好的工厂方法,而非手动 new 原始集合










