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

Kotlin Android 运行时反射匹配类 替换when语句动态解析服务端多类型返回对象

解决方案

核心思路是建立type字段值到对应Tile子类Class对象的映射表,直接替换when分支判断,你可以根据业务场景选择以下两种实现方案:


方案1:手动维护映射(推荐生产环境使用)

无反射开销,逻辑清晰可控,性能最优。后续新增Tile子类时,仅需在映射表中新增一条记录即可,无需修改解析核心逻辑。

sealed class Tile(
    private val id: String,
    private val type: String,
    private val title: String,
) {
    class RedTile(
        id: String,
        type: String,
        title: String,
        val stuff: String
    ) : Tile(id, type, title) {
        companion object {
            const val TYPE = "RedTile"
        }
    }
    class BlueTile(
        id: String,
        type: String,
        title: String,
        val value: Int
    ) : Tile(id, type, title) {
        companion object {
            const val TYPE = "BlueTile"
        }
    }

    companion object {
        // 维护type到对应类的映射表
        private val tileTypeMapping = mapOf(
            RedTile.TYPE to RedTile::class.java,
            BlueTile.TYPE to BlueTile::class.java
        )
        // 复用Gson实例,避免重复创建
        private val gson = Gson()

        fun parseArray(jsonArrayString: String): List<Tile> {
            return JsonParser.parseString(jsonArrayString).asJsonArray
                .map { tileJsonObject ->
                    tileJsonObject as JsonObject
                    val typeValue = tileJsonObject.get("type").asString
                    // 直接从映射表取对应类,不存在则用RedTile兜底
                    val tileClass = tileTypeMapping.getOrDefault(typeValue, RedTile::class.java)
                    gson.fromJson(tileJsonObject, tileClass)
                }
        }
    }
}

方案2:自动反射扫描(完全动态)

无需手动维护映射表,新增Tile子类时不需要修改任何原有代码,自动完成type与类的匹配,适合子类迭代频繁的场景。
需先在项目中引入Kotlin反射依赖(版本和你项目的Kotlin版本保持一致):

// build.gradle.kts 依赖配置
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.0")

完整实现代码:

sealed class Tile(
    private val id: String,
    private val type: String,
    private val title: String,
) {
    class RedTile(
        id: String,
        type: String,
        title: String,
        val stuff: String
    ) : Tile(id, type, title) {
        companion object {
            const val TYPE = "RedTile"
        }
    }
    class BlueTile(
        id: String,
        type: String,
        title: String,
        val value: Int
    ) : Tile(id, type, title) {
        companion object {
            const val TYPE = "BlueTile"
        }
    }

    companion object {
        // 自动扫描所有密封子类,生成映射表
        private val tileTypeMapping = Tile::class.sealedSubclasses.associate { kClass ->
            // 读取子类伴生对象中的TYPE常量作为key
            val typeValue = kClass.companionObject?.members?.find { it.name == "TYPE" }?.call() as String
            typeValue to kClass.java
        }
        private val gson = Gson()

        fun parseArray(jsonArrayString: String): List<Tile> {
            return JsonParser.parseString(jsonArrayString).asJsonArray
                .map { tileJsonObject ->
                    tileJsonObject as JsonObject
                    val typeValue = tileJsonObject.get("type").asString
                    val tileClass = tileTypeMapping.getOrDefault(typeValue, RedTile::class.java)
                    gson.fromJson(tileJsonObject, tileClass)
                }
        }
    }
}

额外优化建议

  • 如果业务不允许未知type默认返回RedTile,可以在取不到对应类的时候抛出业务异常,方便后续监控上报异常数据。
  • 如果你的项目使用Jackson等其他序列化框架,只需要替换Gson相关逻辑即可,映射表的思路通用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:24:09