typetoken 通过匿名子类将泛型签名固化到字节码中以绕过类型擦除,而 class 无法表示带通配符的嵌套泛型,因其仅标识原始类型(如 list.class),不保存泛型参数及通配符信息。

TypeToken 是 Gson 库中用于在运行时保留泛型类型信息的工具,它通过匿名子类的方式“捕获”泛型参数,从而绕过 Java 的类型擦除机制。但要注意:它并不能真正“恢复”已擦除的类型,而是利用 Java 编译器为匿名内部类生成的 Signature 和 GenericSuperclass 元数据,在编译期把泛型信息固化到字节码中,再在运行时读取。
为什么普通 Class 无法表示带通配符的嵌套泛型?
Java 的 Class 类型只代表具体类型(如 List.class),不携带泛型参数;而像 List extends Number> 或 Map<string list super integer>></string> 这类含通配符的嵌套泛型,必须用 Type(尤其是 ParameterizedType、WildcardType)才能完整表达。直接写 new ArrayList extends Number>().getClass() 会失败——语法非法,且擦除后只剩 ArrayList。
用 TypeToken 捕获含通配符的嵌套泛型
关键在于创建一个匿名子类,并在其构造中传入目标泛型类型——编译器会把该类型写入子类的泛型父类签名里:
- 写法示例:获取
Map<string list extends number>></string>
new TypeToken
- 这个空花括号创建了
TypeToken的匿名子类,其getRawType()返回Map.class,getType()返回完整的ParameterizedType实例,其中第二个类型参数是WildcardType(对应? extends Number) - 注意:必须用大括号
{},不能省略;也不能赋值给变量后再调用getType(),否则泛型信息丢失 - 嵌套层级不限,比如
Response<result super string>>></result>同样适用
配合 Gson 解析含通配符的 JSON
Gson 本身不支持直接反序列化含通配符的类型(因为运行时无法确定通配符边界的具体实例),但 TypeToken 可以让 Gson 知道“期望的结构”:
- 定义一个实际可实例化的替代类型(如用
Number代替? extends Number),再借助TypeToken告知 Gson 结构意图 - 例如:JSON 是
{"data":[1.5, 2]},想映射为Map<string list extends number>></string>,可先用TypeToken<map list>>>() {}</map>解析,再手动转成更宽泛的引用 - 真正需要通配符语义(如只读、协变)时,建议在业务层用接口或上界限定封装,而非强求 Gson 直接产出
? extends T实例
注意事项和常见误区
- 不能用变量保存 TypeToken:
TypeToken<t> token = new TypeToken<t>() {}</t></t>❌ —— 类型T在运行时仍是擦除的,匿名子类的泛型信息来自字面量,不是变量推导 - 通配符类型(
? extends T/? super T)在运行时只能读取上界/下界,不能 new 实例;Gson 构造对象时仍需具体类型 - 若需动态构造复杂泛型(如运行时拼接),可用
TypeBuilder(第三方库)或反射操作java.lang.reflect.ParameterizedType,但复杂度高、易出错
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











