Gson泛型反序列化需用TypeToken获取真实类型,因Java泛型运行时被擦除;必须匿名继承TypeToken并调用getType(),否则无法正确解析嵌套泛型或泛型字段。

泛型反序列化失败:为什么 Gson.fromJson(json, List.class) 拿不到实际类型
Java 运行时擦除泛型信息,List<string></string> 和 List<integer></integer> 在 JVM 里都是 List。直接传 List.class,Gson 只能构造出 ArrayList<linkedtreemap></linkedtreemap>,不是你想要的 List<string></string>。
必须用 TypeToken 告诉 Gson:“我要的是带具体泛型参数的类型”。
-
TypeToken<list>>()</list>是合法写法;但TypeToken<list>>.getType()</list>才是真正要传给fromJson的值 - 别写
new TypeToken<list>>() {}.getClass()</list>—— 这拿到的是匿名子类的 Class,不是 Type - 如果泛型嵌套深(比如
Map<string list object>>></string>),手写TypeToken很容易括号错位,建议拆成变量 + 注释
TypeToken 必须匿名继承:为什么不能直接 new 构造
TypeToken 的设计依赖 Java 的「匿名内部类保留泛型签名」这一冷特性。只有通过 new TypeToken<...>() {}</...> 这种带大括号的写法,JVM 才会在字节码里存下泛型实参(如 String)。
下面这几种都错:
立即学习“Java免费学习笔记(深入)”;
-
new TypeToken<list>>()</list>—— 缺少{},编译不过 -
TypeToken.getParameterized(List.class, String.class)—— 这是 Gson 2.8+ 提供的替代方案,但只支持一层泛型,Map<string list>></string>就搞不定 - 把
TypeToken存成字段再复用 —— 如果字段是泛型类的成员,类型可能被再次擦除,结果不可靠
自定义类含泛型字段:不显式传 TypeToken 就会丢数据
比如有个类 Response<t></t>,里面字段是 T data。即使你写了 Response<user> res = gson.fromJson(json, Response.class)</user>,data 字段也会变成 LinkedTreeMap,而不是 User。
必须为整个类型构造 TypeToken:
Type type = new TypeToken<Response<User>>() {}.getType();
Response<User> res = gson.fromJson(json, type);
注意点:
- 别漏掉
.getType(),否则传的是TypeToken实例本身,Gson 不认识 - 如果
User本身也含泛型(比如User<Profile>),那就得写成TypeToken<Response<User<Profile>>>(),括号要对齐 - Android 上 ProGuard 可能移除匿名类的泛型信息,需保留
-keep class com.google.gson.reflect.TypeToken { *; }和对应泛型类
泛型数组和基本类型包装类的坑
Gson 对 int[]、boolean[] 支持良好,但对 Integer[]、Boolean[] 默认反序列化成 Object[],再强转会报 ClassCastException。
解决方式统一:用 TypeToken 明确指定数组类型。
Integer[] arr = gson.fromJson(json, new TypeToken<integer>() {}.getType());</integer>- 原始类型数组(如
int[])可以直接用int[].class,不用TypeToken - 千万别用
new TypeToken<int[]>() {}—— Java 不允许基本类型作为泛型实参,编译失败
泛型解析最麻烦的地方不在语法,而在你得时刻想清楚:这个类型在运行时到底有没有足够信息让 Gson 推出来。一不留神,LinkedTreeMap 就悄悄混进你的列表里了。


















