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

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)
            }
        }
    }
}

关键说明

  1. 权限开启:通过prop.isAccessible = true获取私有属性的访问权限,因为Kotlin数据类的属性字段默认是私有。
  2. 嵌套处理:递归遍历所有嵌套的数据类,确保深层属性的非空值也能被更新。
  3. 空值判断:仅当newValue的属性值不为空时才执行更新,避免覆盖cache中已有的有效数据。
  4. 不可变属性修改:虽然数据类属性是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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:02:39