GSON反序列化ClassCastException:嵌套List<List<MyClass>>转换失败
这个问题我之前也碰到过,其实核心是两个关键点:Gson对嵌套泛型的处理逻辑,以及你代码里多余的ObjectOutputStream/ObjectInputStream使用,咱们一步步拆解来看:
为什么会出现这个异常?
嵌套泛型的类型擦除问题:
当你用TypeToken<T>指定List<List<MyClass>>时,Gson能识别外层是List,但解析内层List的时候,由于Java的泛型类型擦除,Gson无法自动推断内层List的元素是MyClass,所以会把JSON里的对象默认反序列化为LinkedTreeMap(Gson的默认Map实现)。为什么
readFromCache的类型转换没报错?
泛型在运行时是被擦除的,JVM只知道readFromCache返回的是List,但不知道内层元素的具体类型。所以as? T的类型检查只会到外层List这一层,不会深入检查内层元素,直到你调用list.first().first()时,才会尝试把LinkedTreeMap强转为MyClass,这时候才会抛出ClassCastException。多余的Object流操作:
你现在的代码是先用Gson把对象转成JSON字符串,再用ObjectOutputStream把这个字符串序列化到文件;读取时又用ObjectInputStream把字符串读出来,再交给Gson反序列化。这完全是多此一举——ObjectOutputStream是用来序列化Java对象的,而Gson已经把对象转成了可直接保存的JSON字符串,这一层操作不仅没用,还可能引入不必要的复杂度。
解决方案:去掉多余的Object流,直接读写JSON字符串
最直接的修复方式是移除ObjectOutputStream和ObjectInputStream,直接用文件读写操作来保存和读取Gson生成的JSON字符串:
修改后的写入函数
inline fun <reified T> writeInCache(content: T, file: File) { val gson = Gson() // 用TypeToken明确指定完整的泛型类型 val json = gson.toJson(content, object : TypeToken<T>() {}.type) // 直接将JSON字符串写入文件 file.writeText(json) }
修改后的读取函数
inline fun <reified T> readFromCache(file: File): T? { if (!file.exists()) return null val json = file.readText() // 同样用TypeToken传递完整的泛型类型信息 return Gson().fromJson(json, object : TypeToken<T>() {}.type) as? T }
这样修改后,Gson可以通过TypeToken获取到完整的List<List<MyClass>>类型信息,反序列化时会正确地把内层元素解析为MyClass,而不是LinkedTreeMap,调用list.first().first()时就不会再抛出类型转换异常了。
额外说明
如果你的项目中需要更复杂的序列化配置(比如自定义日期格式、空值处理等),建议创建一个全局的Gson实例,而不是每次调用都新建一个,这样既可以统一配置,也能提升性能:
// 全局Gson实例,可根据需求配置 val gson = GsonBuilder() .setDateFormat("yyyy-MM-dd HH:mm:ss") .serializeNulls() .create() // 然后在函数中使用这个全局实例 inline fun <reified T> writeInCache(content: T, file: File) { val json = gson.toJson(content, object : TypeToken<T>() {}.type) file.writeText(json) }
内容的提问来源于stack exchange,提问作者Wimps

