Kotlin中如何通过反射将实例非空属性值复制到另一实例
问题:基于反射实现Kotlin数据类嵌套非空属性的增量更新
我定义了如下Kotlin数据类:
data class Test( val one: Int?, val two: Int?, val three: Three?, ){ data class Three( val four: Int?, val five: Five?, ){ data class Five( val six: Int?, val seven: Int?, ) } }
声明了该类的实例变量:
val cache: Test = Test()
另有一个函数会返回仅设置了部分属性的Test实例:
fun onValueUpdated(newValue: Test){ // 当newValue的任意属性不为空时,更新cache的值 // 示例:若newValue = Test( two = 2 ) // 需将cache的two属性更新为2,且不影响其他属性值 }
请问是否存在基于反射的方法,无需手动逐个更新属性,就能根据newValue更新cache的值?期望实现如下函数,将newValue中所有非空值(包括嵌套属性)复制到cache:
fun updateCache(newValue: Test, cache: Test){ //...... // 将newValue中所有非空值复制到cache(包括嵌套属性) // }
实现方案
可以通过Kotlin反射实现这个需求,核心逻辑是递归遍历数据类的所有属性,仅当newValue中的属性值不为空时,覆盖cache对应属性的值。注意Kotlin数据类属性默认是val,需要通过反射修改其底层字段的值。
具体实现代码如下:
import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.jvm.isAccessible fun updateCache(newValue: Any, cache: Any) { // 获取当前类的所有声明属性 val properties = newValue::class.declaredMemberProperties properties.forEach { prop -> prop.isAccessible = true val newValuePropValue = prop.get(newValue) val cachePropValue = prop.get(cache) // 仅处理newValue中非空的属性 if (newValuePropValue != null) { // 判断属性类型是否为数据类,递归处理嵌套结构 if (prop.returnType.classifier?.let { it as? Class<*> }?.isData == true) { // 如果cache对应属性为空,直接赋值newValue的属性;否则递归更新嵌套属性 val target = cachePropValue ?: newValuePropValue updateCache(newValuePropValue, target) prop.set(cache, target) } else { // 非数据类属性直接覆盖赋值 prop.set(cache, newValuePropValue) } } } }
关键说明
- 权限开启:通过
prop.isAccessible = true获取私有属性的访问权限,因为Kotlin数据类的属性字段默认是私有。 - 嵌套处理:递归遍历所有嵌套的数据类,确保深层属性的非空值也能被更新。
- 空值判断:仅当
newValue的属性值不为空时才执行更新,避免覆盖cache中已有的有效数据。 - 不可变属性修改:虽然数据类属性是
val,但反射可以直接修改其底层字段,实现值的更新。
使用示例
fun main() { val cache = Test(one = 1, three = Test.Three(four = 4)) val newValue = Test(two = 2, three = Test.Three(five = Test.Five(seven = 7))) updateCache(newValue, cache) println(cache.one) // 输出1(未修改) println(cache.two) // 输出2(已更新) println(cache.three?.four) // 输出4(未修改) println(cache.three?.five?.seven) // 输出7(已更新) }
内容的提问来源于stack exchange,提问作者user22061875
相关产品推荐
相关产品推荐

