接口返回的是一串 JSON 数组,我用 Gson 直接 fromJson 想转成 List,跑起来就抛 ClassCastException,说 LinkedTreeMap 不能转成 User。第一次碰这问题的基本都卡在这儿。
直接传 List.class 为什么会崩
Gson 靠泛型信息反序列化。你写 fromJson(json, List.class),编译后泛型被擦除了,它只知道要建个 List,不知道里面装什么,于是默认给你塞 LinkedTreeMap。等到取值时强转 User 就炸了。
正式写法用 TypeToken
正确姿势是拿匿名子类把泛型带过去:
Type type = new TypeToken<List<User>>(){}.getType();
List<User> list = new Gson().fromJson(json, type);这里的花括号 {} 是关键,少了它泛型照样丢。Kotlin 里换 TypeToken 也可以用 object 表达式,本质上都是给编译器留一个带泛型的类型。
实体字段名对不上时的两种办法
- 字段名和 JSON 不一致:在字段上标 SerializedName
- 所有字段都想换成下划线风格:建 Gson 时设 FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
- 要忽略多余字段:默认就忽略,反过来想严格校验要自己配
- 时间字段:用 setDateFormat 指定格式,否则按默认解析
嵌套 List 与泛型类
如果实体里还有 List 字段,TypeToken 一样能写:
new TypeToken<Result<List<User>>>(){}.getType()外层是包装类 Result,里面套数组,一层层照写就行。真要动态反射,TypeToken 用不了,得上 TypeAdapter 或者 JsonDeserializer 自己解析。
记牢一点:Gson 解析集合一律用 TypeToken,别图快写 List.class,这是百分之九十的报错来源。数据量大、还想省内存,就换 JsonReader 流式读。