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
相关产品推荐
相关产品推荐

