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

如何对使用属性委托的Kotlin对象实现深度克隆

适配Kotlin属性委托场景的深度克隆解决方案

Apache BeanUtils 是基于Java反射实现的工具,无法识别Kotlin特有的属性委托语法结构,因此不适用于该场景,可选择以下3种落地性强的方案:


方案1:使用kotlinx.serialization序列化反序列化实现(最稳定推荐)

原理是通过Kotlin官方序列化框架将对象转为二进制流,再反序列化为全新对象,原生兼容属性委托、内部类等Kotlin专属语法特性,不会出现属性读取异常。

实现步骤

  1. 给所有参与克隆的类(包括外层类、内部类、自定义委托类)添加@Serializable注解:
import kotlinx.serialization.Serializable

@Serializable
class Model {
    val p1: String by Delegate()
    @Serializable
    inner class InnerModel {
        val p2: String by Delegate()
    } 
    val m = InnerModel()
}

// 自定义委托类也需要实现序列化
@Serializable
class Delegate<T> : ReadWriteProperty<Any?, T> {
    // 原有委托逻辑保持不变
}
  1. 实现通用深度克隆扩展方法:
import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray

inline fun <reified T> T.deepClone(): T {
    val bytes = ProtoBuf.encodeToByteArray(this)
    return ProtoBuf.decodeFromByteArray(bytes)
}
  1. 调用效果完全符合预期:
val m1 = Model()
val m2 = m1.deepClone()

m1.m.p2 = "asd"
assertNotEquals(m1.m.p2, m2.m.p2) // 断言正常通过

方案2:自定义Kotlin反射实现克隆

如果无法给业务类添加序列化注解,可以通过Kotlin反射遍历所有属性(包括委托属性的后备存储字段)手动完成复制:

import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.isAccessible

fun Any.deepClone(): Any {
    // 不可变基础类型直接返回
    val clazz = this::class.java
    if (clazz.isPrimitive || this is String || this is Number || this is Boolean) {
        return this
    }
    // 处理集合类型
    if (this is Collection<*>) return this.map { it?.deepClone() }
    if (this is Map<*, *>) return this.mapValues { it.value?.deepClone() }
    
    // 反射创建类实例
    val constructor = this::class.constructors.first { it.parameters.isEmpty() }
    constructor.isAccessible = true
    val newInstance = constructor.call()
    
    // 复制所有属性值(包含委托属性)
    this::class.declaredMemberProperties.forEach { prop ->
        prop.isAccessible = true
        val clonedValue = prop.get(this)?.deepClone()
        if (prop is kotlin.reflect.KMutableProperty<*>) {
            prop.setter.call(newInstance, clonedValue)
        }
    }
    return newInstance
}

inline fun <reified T> T.clone(): T = deepClone() as T

方案3:使用Kotlin专属克隆库

直接使用针对Kotlin特性开发的克隆库如klone,这类库原生支持属性委托、内部类、数据类的深度克隆,无需额外配置,引入依赖后直接调用klone()方法即可实现需求。

通用注意事项

如果你的自定义委托类持有可变状态,需要确保克隆过程中委托实例本身也被深度复制,而非仅复制引用,否则依然会出现新旧对象属性联动修改的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 07:09:04