Fastjson2 泛型与 TypeReference
作为 Java 开发者,相信你一定遇到过这样的场景:从 JSON 字符串反序列化时,明明写了 List<User>,结果运行却报类型转换异常。原因很简单——泛型在运行时会被擦除。Fastjson2 通过 TypeReference 解决了这个痛点。接下来讲解Fastjson2泛型和 TypeReference 的问题。
泛型擦除带来的问题
Java 的泛型是编译期特性,运行时 JVM 并不知道具体的泛型类型。看个例子:
// 定义一个简单的 User 类
@Data
public class User {
public String name;
public int age;
}
String json = "[{\"name\":\"张三\",\"age\":20},{\"name\":\"李四\",\"age\":25}]";
List<User> userList = JSON.parseObject(json, List.class); // 编译通过,但运行使用时报错
for (User user: userList) {
System.out.println(user.getName());
}
以上报错内容为 Exception in thread "main" java.lang.ClassCastException: com.alibaba.fastjson2.JSONObject cannot be cast to com.example.domain.User虽然编译不报错,但 List.class 并没有保留 User 类型信息,返回的是 List<Object>,使用时会抛出 ClassCastException。
TypeReference 泛型
Fastjson2 提供了 TypeReference 抽象类,用于在运行时保存泛型信息。让我们修复上面的问题:
import com.alibaba.fastjson2.TypeReference;
// 正确写法
List<User> userList = JSON.parseObject(json, new TypeReference<List<User>>(){}.getType());
// 或者更简洁的 Lambda 写法(Fastjson2 特有)
List<User> userList = JSON.parseObject(json, new TypeReference<List<User>>(){});
关键点:new TypeReference<List<User>>(){} 创建了一个匿名内部类,通过子类化保留了泛型参数。这就是“利用超类型令牌(Super Type Token)”技术。
复杂泛型的处理
对于嵌套泛型,TypeReference 同样高效:
// Map 中的 Value 是 List<User>
String json = "{\"group1\":[{\"name\":\"张三\",\"age\":20}],\"group2\":[{\"name\":\"李四\",\"age\":25}]}";
Map<String, List<User>> map = JSON.parseObject(json,
new TypeReference<Map<String, List<User>>>(){});
for (String key : map.keySet()) {
List<User> users = map.get(key);
System.out.println("分组:" + key);
users.forEach(System.out::println);
}
输出结果
分组:group2
User(name=李四, age=25)
分组:group1
User(name=张三, age=20)
甚至可以处理泛型中的泛型,常用于api返回值处理:
// 定义一个泛型响应类
public class Result<T> {
public int code;
public T data;
}
// 反序列化时指定 T 的具体类型
String json = "{\"code\":200,\"data\":{\"name\":\"王五\",\"age\":30}}";
Result<User> result = JSON.parseObject(json, new TypeReference<Result<User>>(){});
类型安全的 JSON 工具方法
封装一个工具类让调用更优雅:
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
public class JsonUtil {
// 带泛型的反序列化
public static <T> T parseJson(String json, TypeReference<T> typeRef) {
return JSON.parseObject(json, typeRef);
}
// 从文件读取
public static <T> T parseFromFile(String filePath, TypeReference<T> typeRef) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
return parseJson(content, typeRef);
}
}
// 使用示例
List<User> users = JsonUtil.parseJson(json, new TypeReference<List<User>>(){});
注意事项
- 必须使用匿名内部类:
new TypeReference<T>(){}的大括号不能省略,否则泛型信息依然丢失 - 性能影响:每次创建匿名类会略有开销,但通常可以忽略。对于高频调用可考虑缓存
Type对象 - 与 Java 8+ 函数式接口区别:TypeReference 不是函数式接口,不能使用 Lambda 表达式替代(但 Fastjson2 的
parseObject有重载支持 Lambda 写法时除外)
总结
Java 泛型会丢失类型,很容易出问题。Fastjson2 的 TypeReference 就是用来解决这个问题的,能准确解析泛型类型。无论你是处理简单的 List<User>,还是复杂的 Result<Map<String, List<Order>>>,TypeReference 都能帮你做到类型安全、零强制转换。

