泛型是 Java 基础中的核心知识点,从语法使用到底层原理,再到实际开发中的常见误区,很多开发者虽然经常使用,但理解并不深入。本文从泛型擦除、通配符、上下界、反射与泛型、常见错误几个方面做一次完整梳理,属于纯语言基础总结,无任何业务场景、无商业内容、无外部关联,适合后端学习者参考。
一、什么是泛型擦除
Java 的泛型并非真正的运行时泛型,而是编译期泛型。编译器在编译完成后,会移除所有泛型类型信息,只保留原始类型(Raw Type)。
例如:
plaintext
List<String> list = new ArrayList<>();
编译后等同于:
plaintext
List list = new ArrayList();
泛型仅存在于 .java 文件中, .class 中无泛型信息。这就是所谓的类型擦除(Type Erasure) 。
二、泛型擦除带来的限制
因为擦除机制,Java 泛型存在一些天然限制:
- 不能使用基本类型
List<int>不合法,必须用List<Integer>。 - 不能创建泛型数组
T[] arr = new T[10];编译报错。 - 不能判断泛型类型
if (list instanceof List<String>)不允许。 - 不能实例化泛型对象
new T()无法通过编译。 - 静态方法不能使用类泛型因为类泛型属于对象,不属于类本身。
理解这些限制,是避免写出 Bug 的关键。
三、? 通配符:? extends T 与?super T
很多开发者对通配符理解模糊,这里用最简单方式总结:
- ? extends T:生产者(只能读,不能写)表示 “T 或 T 的子类”,只能取,不能存。
- ? super T:消费者(只能写,不能读)表示 “T 或 T 的父类”,只能存,不能安全取。
经典总结:PECS 原则Producer Extends,Consumer Super。
四、泛型与反射的注意点
由于泛型被擦除,通过反射获取泛型信息时,只能从:
- 字段
- 方法参数
- 方法返回值
获取泛型签名信息,而无法从对象实例获取。
例如:
java
运行
Method method = UserService.class.getMethod("getList");
Type type = method.getGenericReturnType();
这种方式可以拿到泛型,但属于元数据信息,不是运行时类型。
五、开发中最常见的泛型误区
- 以为泛型在运行时存在导致写出错误的类型判断逻辑。
- List 不是 List 的父类泛型不具备多态性,很多初学者踩坑。
- 泛型方法与泛型类混淆类泛型属于对象,方法泛型属于方法自身。
- 过度使用通配符导致代码可读性下降、调用复杂。
- 忽略泛型转换警告
@SuppressWarnings("unchecked")乱用容易引发类型转换异常。六、正确使用泛型的建议
- 优先使用泛型类、泛型接口,提高代码复用。
- 尽量使用边界限定,避免使用无限制
<?>。 - 遵循 PECS 原则,使接口更清晰。
- 不要忽视编译警告,泛型警告基本都是真实风险。
- 公共工具类必须使用泛型,保证类型安全。
七、总结
泛型本质是编译器语法糖 + 类型检查,底层依靠类型擦除实现。理解擦除机制、通配符区别、常见误区,能有效避免大量隐藏 Bug。
Java 基础看似简单,但很多细节决定了代码健壮性。泛型作为高频使用特性,值得每一位后端开发者彻底掌握。