type token 是通过匿名子类捕获泛型信息以绕过类型擦除的技巧,用于反序列化、反射等需运行时获取参数化类型(如 list)的场景,核心依赖 getclass().getgenericsuperclass() 提取泛型父类信息。

Java 泛型在编译期被擦除,运行时无法获取具体的泛型类型(如 List<string></string> 擦除后只剩 List),这导致反序列化、反射、泛型工厂等场景无法获知实际类型参数。类型标记(Type Token)是一种通过匿名子类“捕获”泛型信息的惯用技巧,本质是利用 java.lang.reflect.Type 和类加载时保留的泛型父类信息来绕过类型擦除。
为什么需要 Type Token?
泛型擦除让以下操作无法直接进行:
- 从 JSON 字符串反序列化为
List<user></user>,而不仅仅是List - 在运行时判断某个
Field的泛型类型是否为Map<string integer></string> - 构建通用的泛型 DAO 或缓存工具,需按实际类型区分缓存键或 SQL 映射
单纯传入 Class<t></t> 不够(它只能表示原始类型,如 String.class,不能表示 List<string></string> 这种带参数化类型的结构),而 Type Token 可以承载完整的参数化类型信息。
如何构造一个 Type Token
核心思路:定义一个抽象类(如 TypeToken<t></t>),在子类中用匿名内部类继承它,并在构造时通过 getClass().getGenericSuperclass() 获取带泛型的父类类型。
例如:
public abstract class TypeToken<t> {
private final Type type;
protected TypeToken() {
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
}</t>
使用时写成:
通过 Palebluedot AI(PBD)-TokenRouter 的多模态图像生成端点(`/v1/chat/completions`)使用 TokenRouter 兼容的方式生成或编辑图像...
TypeToken<list>> stringListToken = new TypeToken<list>>() {};
// 注意末尾的 {} —— 创建匿名子类实例,使泛型信息保留在字节码中</list></list>
此时 stringListToken.getType() 返回的就是 ParameterizedType 实例,可准确解析出 List 及其类型参数 String。
典型应用场景:Gson 反序列化
Gson 的 fromJson(String, Type) 方法接受 Type 而非 Class,正是为了支持泛型结构:
List<user> users = gson.fromJson(json, new TypeToken<list>>() {}.getType());</list></user>
同理,Jackson 也提供类似机制(TypeReference<t></t>),其实现原理几乎一致——都是靠匿名子类固化泛型签名。
注意事项与限制
Type Token 并非万能,有几点必须清楚:
- 必须用匿名子类方式创建(
new TypeToken<...>() {}</...>),直接 new 会丢失泛型信息 - 不支持运行时动态拼接类型(如根据字符串构造
List<t></t>),因为类型信息必须在编译期确定并写入字节码 - 嵌套过深或含通配符(
? extends Number)时,解析逻辑需更谨慎,建议配合TypeResolver工具类(如 Guava 的TypeResolver)处理 - 不能用于数组类型(
T[])的泛型推导,因数组类型在 JVM 中是协变且不保留泛型元数据
本质上,Type Token 是对 Java 类型系统局限性的优雅妥协——它不改变擦除规则,而是把类型契约“提前固化”到类结构里,再靠反射读出来。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










