Java泛型不是语法糖,而是编译期类型安全的基石,其核心在于理解擦除、不变性与类型推断三支柱,并在泛型类、泛型方法、通配符及擦除应对中自然落地。

Java 泛型不是语法糖,而是编译期类型安全的基石。写好泛型,关键不在堆砌概念,而在理解“擦除”“不变性”“类型推断”这三根支柱,并在日常编码中自然落地。
泛型类:从容器开始建模
定义一个泛型类时,本质是在抽象“结构”与“行为”,而非绑定具体类型。比如实现一个通用结果包装器:
- 用 T 表示数据主体类型,E 表示错误类型(如
Result<User, ValidationErrors>) - 字段、构造器、getter/setter 全部基于类型参数,不出现
Object或强转 - 避免在泛型类里直接 new T() —— 类型擦除后无法实例化,改用 Supplier<T> 或 Class<T> 参数传递
泛型方法:比泛型类更轻量、更常用
多数工具逻辑不需要整个类泛型化,一个静态方法就够了。典型场景如数组取值、集合转换、空值校验:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 声明位置必须在返回类型前:
public static <T> T first(List<T> list) - 编译器通常能自动推断类型实参,调用时无需写
Utils.<String>first(...),直接Utils.first(stringList)即可 - 多个类型参数可共存:
<K, V> Map<K, V> of(K k, V v),适合构建短生命周期结构
通配符:解决泛型的“父子关系”困境
Java 泛型是不变的(invariant),List<String> 不是 List<Object> 的子类型。通配符就是为此而生:
立即学习“Java免费学习笔记(深入)”;
-
List<? extends Number>:只读,可取Number及其子类(Integer、Double),但不能 add(除了null) -
List<? super Integer>:只写,可 addInteger及其子类(如AtomicInteger),但取出来只能当Object - 不要滥用
List<?>,它等价于原始类型,失去类型约束,仅用于反射或跨模块兼容场景
绕不开的擦除:接受限制,善用技巧
泛型信息在运行时不存在,这是 Java 的设计选择,带来明确限制,也催生实用技巧:
- 不能用
instanceof T,也不能new T[10];需要数组时用(T[]) new Object[10](配合@SuppressWarnings("unchecked")) - 反射获取泛型实际类型?只能通过
Method.getGenericReturnType()或字段的Field.getGenericType(),且仅限带泛型声明的成员(如private List<String> names;) - 序列化/反序列化泛型对象?依赖库(如 Gson 的
TypeToken、Jackson 的TypeReference)手动补全擦除丢失的信息


















