如何访问嵌套在data class内部的data class属性值
核心原因
你定义的A.data字段类型为Any,Kotlin作为静态类型语言,编译器默认只能识别该字段是通用对象类型,无法直接推断其实际存储的是A.B还是A.C实例,必须先通过类型检查确认实际类型,完成安全转换后才能访问对应类的属性。
标准访问方式
Kotlin提供了智能转换机制,配合is类型检查可以零成本安全访问属性,最推荐用when分支处理不同类型的场景:
// 入参a为A类的实例 fun parseAData(a: A) { when (a.data) { is A.B -> { // 类型检查通过后,当前代码块内a.data会被自动智能转换为A.B类型,可直接访问属性 println("解析到B类数据,姓名:${a.data.name},手机号:${a.data.phone}") } is A.C -> { // 同理,当前块内a.data自动转为A.C类型 println("解析到C类数据,姓名:${a.data.name},手机号:${a.data.phone}") } else -> { // 处理data字段既不是B也不是C的异常场景 println("数据类型不合法") } } }
如果你已经通过type字段做了类型约定(比如约定type=1时data存B实例,type=2时存C实例),也可以结合安全转换符as?做处理,避免强转崩溃:
val a: A = getSourceA() val parseResult = when (a.type) { 1 -> { val bInstance = a.data as? A.B bInstance?.let { "B类数据:name=${it.name},phone=${it.phone}" } ?: "类型匹配失败,预期为B类实例" } 2 -> { val cInstance = a.data as? A.C cInstance?.let { "C类数据:name=${it.name},phone=${it.phone}" } ?: "类型匹配失败,预期为C类实例" } else -> "未知type标识" } println(parseResult)
注意:不要直接使用非安全转换符
as强转(比如a.data as A.B),如果data实际存储的是其他类型,会直接抛出ClassCastException导致程序崩溃。
更优实现建议
你当前用「Int类型type标记 + Any存数据」的写法很容易出现type和实际存储类型不匹配的问题,更符合Kotlin语言特性的方案是用密封类(sealed class)做类型约束,从根源上避免类型判断错误:
sealed class A { abstract val type: Int data class B( override val type: Int = 1, val name: String, val phone: String ) : A() data class C( override val type: Int = 2, val name: String, val phone: String ) : A() }
这种写法下不需要单独定义Any类型的data字段,B和C本身就是A的子类,编译器会自动校验类型分支是否完整,不需要写多余的else分支:
fun parseA(a: A) { when (a) { is A.B -> println("B类数据:${a.name},${a.phone}") is A.C -> println("C类数据:${a.name},${a.phone}") } }
内容的提问来源于stack exchange,提问作者Ankesh Roy
相关产品推荐
相关产品推荐

