Fastjson 1 泛型与 TypeReference

在做Java项目开发的时候,你在使用 Fastjson 1 时一定遇到过这样的情况:明明写对了 JSON 字符串,解析后却得到了意想不到的结果,甚至抛出异常。这通常是因为没有正确处理泛型信息。现在介绍Fastjson 1 中的泛型解析利器 TypeReference

为什么需要 TypeReference?

Java 的泛型在运行时会被擦除(Type Erasure)。例如 List<User> 在运行时只会被当成 List 处理,失去了 User 的类型信息。当你用 JSON.parseObject(json, List.class) 时,Fastjson 并不知道列表里装的是什么类型,只能默认转换为 JSONObjectJSONArray

看一个典型错误例子:

String json = "[{\"name\":\"张三\"}, {\"name\":\"李四\"}]";
List<User> users = JSON.parseObject(json, List.class); 
List userList = JSON.parseObject(json, List.class); // 编译通过,但运行使用时报错
for (User user: userList) {
	System.out.println(user.getName());
} 

这里编译没有问题,但运行后 users 里的元素其实是 JSONObject,不是 User,报错信息为 Exception in thread "main" java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.example.domain.User

TypeReference 介绍

TypeReference 是 Fastjson 提供的一个抽象类,用于在运行时保留泛型类型信息。它的用法是:创建一个匿名内部类,通过子类来捕获父类的泛型参数。

基本语法

import com.alibaba.fastjson.TypeReference;

// 保留 List<User> 的类型信息
TypeReference<List<User>> typeRef = new TypeReference<List<User>>() {};
List<User> users = JSON.parseObject(json, typeRef);

注意:new TypeReference<List<User>>() {} 末尾的 {} 一定要有,表示创建匿名子类。

实战示例

解析泛型 List

public class User {
    public String name;
    public int age;
}

public class Demo {
    public static void main(String[] args) {
        String json = "[{\"name\":\"Tom\",\"age\":25},{\"name\":\"Jerry\",\"age\":23}]";

        // 错误方式:泛型信息丢失
        List list = JSON.parseObject(json, List.class);
        Object first = list.get(0);
        System.out.println(first.getClass()); // class com.alibaba.fastjson.JSONObject

        // 正确方式:使用 TypeReference
        List<User> users = JSON.parseObject(json, 
            new TypeReference<List<User>>() {});
        User user = users.get(0);
        System.out.println(user.name); // Tom
        System.out.println(user.getClass()); // class User
    }
}

解析复杂嵌套泛型

比如 Map<String, List<Integer>> 这种类型:

String json = "{\"scores\":[90,85,92],\"grades\":[95,88]}";
Map<String, List<Integer>> map = JSON.parseObject(json,
    new TypeReference<Map<String, List<Integer>>>() {});
System.out.println(map.get("scores").get(0)); // 90

解析api数据的例子

String resultJson = "{\"code\":200,\"data\":[{\"name\":\"Tom\",\"age\":25}]}";

// 定义泛型类
class Result<T> {
    public int code;
    public T data;
}

// 正确解析方式
Result<List<User>> result = JSON.parseObject(resultJson, 
    new TypeReference<Result<List<User>>>() {});
System.out.println(result.data.get(0).name);  // Tom

作为方法参数传递

当你封装工具方法时,TypeReference 非常有用:

public static <T> T parseGeneric(String json, TypeReference<T> typeRef) {
    return JSON.parseObject(json, typeRef);
}

// 调用
List<User> users = parseGeneric(json, new TypeReference<List<User>>() {});

背后的原理

Fastjson 通过 TypeReferencegetType() 方法获取到完整的泛型类型(例如 java.util.List<com.example.User>),从而在反序列化时知道如何处理内部元素。这个技巧利用了 Java 匿名内部类在编译时会记录父类泛型信息的特性。

常见误区

  1. 忘记写 {}new TypeReference<List<User>>() 是错误的,必须写 {} 才能创建匿名子类。
  2. 类型写错:TypeReference 的泛型参数必须与实际 JSON 结构完全匹配。
  3. 混用 parseObject 的重载parseObject(String, Class) 用于无泛型场景,有泛型时必须使用 TypeReference 版本。

总结

记住一个简单原则:只要 JSON 中包含泛型信息(如 List、Map 或自定义泛型类),就使用 TypeReference 来保留类型。这不仅能避免运行时的 ClassCastException,还能让你的代码更健壮、更易维护。