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>>(){});

注意事项

  1. 必须使用匿名内部类new TypeReference<T>(){} 的大括号不能省略,否则泛型信息依然丢失
  2. 性能影响:每次创建匿名类会略有开销,但通常可以忽略。对于高频调用可考虑缓存 Type 对象
  3. 与 Java 8+ 函数式接口区别:TypeReference 不是函数式接口,不能使用 Lambda 表达式替代(但 Fastjson2 的 parseObject 有重载支持 Lambda 写法时除外)

总结

Java 泛型会丢失类型,很容易出问题。Fastjson2 的 TypeReference 就是用来解决这个问题的,能准确解析泛型类型。无论你是处理简单的 List<User>,还是复杂的 Result<Map<String, List<Order>>>,TypeReference 都能帮你做到类型安全、零强制转换。