TypeReference通过匿名子类保留泛型信息,使Jackson能在运行时获取List<User>等完整类型;必须用new TypeReference<List<User>>(){}形式,不可直接实例化或在泛型方法中使用T。

Java 泛型在运行时被擦除,所以 Jackson 无法单靠 List.class 知道你要反序列化成 List<User> 还是 List<Order>。TypeReference 就是专门用来“绕过擦除”,把泛型信息带进运行时的机制。
为什么 TypeReference 能保留泛型信息
TypeReference 是一个抽象类,它利用了 Java 匿名内部类的一个特性:JVM 会在字节码里保留其父类的泛型签名。当你写 new TypeReference<List<User>>() {},这个空花括号创建了一个匿名子类,Jackson 就能通过反射读取 getGenericSuperclass(),从中提取出 List<User> 的完整类型结构。
- 不是靠泛型参数 T,而是靠编译后保留在 class 文件里的泛型字面量
- 必须是匿名子类写法 ——
new TypeReference<...>() {},不能直接 new TypeReference - 不能用于泛型方法内的动态 T(比如
<T> List<T> parse(String json)),因为此时 T 已被擦除
正确使用 TypeReference 的写法
最常用、最直观的方式就是为具体类型写死一个 TypeReference 实例:
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});Map<String, Product> map = mapper.readValue(json, new TypeReference<Map<String, Product>>() {});Response<Page<Comment>> resp = mapper.readValue(json, new TypeReference<Response<Page<Comment>>>() {});
注意:目标类(如 User)需有无参构造器,字段命名或 getter/setter 需符合 Jackson 默认策略(或配 @JsonProperty)。
立即学习“Java免费学习笔记(深入)”;
替代方案:用 JavaType 构建动态类型
当类型是运行时才确定的(比如封装成通用工具方法),就不能依赖匿名类 —— 此时要用 TypeFactory:
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class, User.class);List<User> users = mapper.readValue(json, type);- 可封装为:
<T> List<T> readList(String json, Class<T> elementType) { ... } - 支持嵌套泛型,比如
constructParametricType(Response.class, constructCollectionType(List.class, Item.class))
常见误区和避坑点
这些写法看似合理,但实际无效或危险:
-
mapper.readValue(json, List.class)→ 返回List<LinkedHashMap>,不是你想要的对象列表 -
new TypeReference<List<T>>() {}(T 是方法泛型)→ 编译可能过,运行时 T 是 Object,反序列化失败 - 非静态内部类作为泛型元素 → Jackson 无法实例化,抛 InstantiationException
- 没加
@JsonIgnoreProperties(ignoreUnknown = true)→ JSON 多字段时直接报 UnrecognizedPropertyException


















