You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中使用GSON实现多态列表反序列化?

解决Gson+Retrofit反序列化多类型列表的问题

这个场景我之前也踩过坑!Gson默认确实没法直接实例化抽象父类,因为它不知道该创建哪个具体子类的实例。下面给你一套可落地的解决方案,分步骤来:

第一步:定义数据类结构

先把三种类型的共享属性抽成抽象父类,三个子类各自实现特有属性:

// 抽象父类,包含所有类型共享的属性
abstract class BaseItem(
    val id: String,
    val name: String
)

// 类型A的子类,特有属性:aField
data class TypeA(
    id: String,
    name: String,
    val aField: Int
) : BaseItem(id, name)

// 类型B的子类,特有属性:bField
data class TypeB(
    id: String,
    name: String,
    val bField: String
) : BaseItem(id, name)

// 类型C的子类,特有属性:cField
data class TypeC(
    id: String,
    name: String,
    val cField: Boolean
) : BaseItem(id, name)

第二步:配置Gson的类型识别逻辑

这里有两种常用方案,选哪种取决于你的数据源是否有明确的类型标识字段:

方案1:用RuntimeTypeAdapterFactory(推荐,简洁高效)

Gson的扩展库提供了这个工厂类,可以根据指定字段自动匹配子类。首先需要添加依赖(以Gradle Kotlin DSL为例):

implementation("com.google.code.gson:gson-extras:2.10.1")

然后创建Gson实例时注册这个工厂,假设你的数据源返回的JSON里有type字段(值为"A"/"B"/"C")用来标识类型:

// 创建类型适配器工厂,绑定父类和类型字段
val typeAdapterFactory = RuntimeTypeAdapterFactory.of(BaseItem::class.java, "type")
    .registerSubtype(TypeA::class.java, "A")
    .registerSubtype(TypeB::class.java, "B")
    .registerSubtype(TypeC::class.java, "C")

// 构建带类型识别能力的Gson实例
val gson = GsonBuilder()
    .registerTypeAdapterFactory(typeAdapterFactory)
    .create()

方案2:自定义TypeAdapter(灵活,适合无明确类型字段的场景)

如果你的数据源没有专门的type字段,只能通过特有属性判断(比如是否存在aField),就自己写适配器:

class BaseItemTypeAdapter : TypeAdapter<BaseItem>() {
    override fun write(out: JsonWriter, value: BaseItem?) {
        // 序列化逻辑,若不需要序列化可忽略,或根据子类类型写入对应字段
        val gson = Gson()
        when (value) {
            is TypeA -> gson.toJson(value, TypeA::class.java, out)
            is TypeB -> gson.toJson(value, TypeB::class.java, out)
            is TypeC -> gson.toJson(value, TypeC::class.java, out)
            else -> throw IllegalArgumentException("Unknown item type: ${value?.javaClass}")
        }
    }

    override fun read(`in`: JsonReader): BaseItem {
        // 先解析成JsonObject,再根据特有属性判断类型
        val jsonObject = JsonParser.parseReader(`in`).asJsonObject
        return when {
            jsonObject.has("aField") -> Gson().fromJson(jsonObject, TypeA::class.java)
            jsonObject.has("bField") -> Gson().fromJson(jsonObject, TypeB::class.java)
            jsonObject.has("cField") -> Gson().fromJson(jsonObject, TypeC::class.java)
            else -> throw IllegalArgumentException("Unrecognized item type")
        }
    }
}

注册到Gson的方式:

val gson = GsonBuilder()
    .registerTypeAdapter(BaseItem::class.java, BaseItemTypeAdapter())
    .create()

第三步:把配置好的Gson传给Retrofit

最后在构建Retrofit实例时,用我们自定义的Gson替换默认实现:

val retrofit = Retrofit.Builder()
    .baseUrl("你的API基础地址")
    .addConverterFactory(GsonConverterFactory.create(gson)) // 传入自定义的Gson实例
    .build()

// 定义你的API接口
interface DataFeedApi {
    @GET("items")
    suspend fun getItems(): List<BaseItem>
}

这样调用接口时,Retrofit就会用我们配置的Gson正确把JSON列表反序列化成TypeA/TypeB/TypeC的混合列表了!

内容的提问来源于stack exchange,提问作者user1470618

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:03:52