How to clone object in Kotlin?

前端 未结 9 455
清歌不尽
清歌不尽 2020-12-09 07:04

The question is that simple.

Kotlin documentation describes cloning only in accessing Java and in enum class. In latter case clone is just throwing an exception.

相关标签:
9条回答
  • 2020-12-09 07:46

    I've voted for @yole for nice answer, but other ways if you don't (or can't) use data class. You can write helper method like this:

    object ModelHelper {
    
        inline fun <reified T : Serializable> mergeFields(from: T, to: T) {
            from::class.java.declaredFields.forEach { field ->
                val isLocked = field.isAccessible
                field.isAccessible = true
    
                if (field.get(from) != null) {
                    field.set(to, field.get(from))
                }
    
                field.isAccessible = isLocked
            }
        }
    
    }
    

    So you can "copy" instance A into B by:

    val bInstance = AClassType()
    ModelHelper.mergeFields(aInstance, bInstance)
    

    Sometimes, I use this way to merge data from many instances into one object which value available (not null).

    0 讨论(0)
  • 2020-12-09 07:47

    If the class you are trying to clone does not implement Cloneable or is not a data class and is a part of an outside library, you can create an extension method that returns a new instance. For example:

    class Person {
      var id: String? = null
      var name: String? = null
    } 
    fun Person.clone(): Person {
      val person = Person()
      person.id = id
      person.name = name
      return person 
    }
    
    0 讨论(0)
  • 2020-12-09 07:48

    You can use Gson library to convert the original object to a String and then convert back that String to an actual Object type, and you'll have a clone. Although this is not the intended usage of the Gson library which is actually used to convert between JSON and other object types, but I have devised this method to solve the cloning problem in many of my Kotlin based Android applications. See my example. Put this function in the class/model of which you want to create a clone. In my example I'm cloning a Project type object so I'll put it in the Project class

    class Project{
     fun clone(): Project {
                    val stringProject = Gson().toJson(this, Project::class.java)
                    return Gson().fromJson<Project>(stringProject, Project::class.java)
                }
    }
    

    Then use it like this:

    val originalProject = Project()
    val clonedProject = originalProject.clone()
    
    0 讨论(0)
  • 2020-12-09 07:52

    It requires to implement Cloneable for your class then override clone() as a public like:

    public override fun clone(): Any {<your_clone_code>}
    

    https://discuss.kotlinlang.org/t/how-to-use-cloneable/2364/3

    0 讨论(0)
  • 2020-12-09 07:53
    fun <T : Any> clone (obj: T): T {
      if (!obj::class.isData) {
        println(obj)
        throw Error("clone is only supported for data classes")
      }
    
      val copy = obj::class.memberFunctions.first { it.name == "copy" }
      val instanceParam = copy.instanceParameter!!
      return copy.callBy(mapOf(
        instanceParam to obj
      )) as T
    }
    
    
    0 讨论(0)
  • 2020-12-09 07:59

    It's also possible to clone an object using kotlinx.serialization

    import kotlinx.serialization.Serializable
    import kotlinx.serialization.json.Json
    import kotlinx.serialization.json.JsonConfiguration
    
    @Serializable
    class A
    {
        val name: String = "Cloneable class A"
    
        fun clone(): A {
            val json = Json(JsonConfiguration.Stable)
            val jsonStr = json.stringify(serializer(), this)
            return json.parse(serializer(), jsonStr)
        }
    }
    
    0 讨论(0)
提交回复
热议问题