40

I am new to kotlin and I am trying to make a copy of a list of objects.The problem I am having is that when I change items in the new copy, the old list gets changed as well. This is the object:

class ClassA(var title: String?, var list: ArrayList<ClassB>, var selected: Boolean)
class ClassB(val id: Int, val name: String) 

I tried doing this, but it doesn't work:

val oldList:ArrayList<ClassA>


val newList :ArrayList<ClassA> = ArrayList()
newList.addAll(oldList)
Oya
  • 833
  • 1
  • 8
  • 21

3 Answers3

53

That's bacause you are adding all the object references to another list, hence you are not making a proper copy, you have the same elements in two list. If you want diferents list and diferent references, you must clone every object in a new list:

public data class Person(var n: String)

fun main(args: Array<String>) {
    //creates two instances
    var anna = Person("Anna")
    var Alex =Person("Alex")

    //add to list
    val names = arrayOf(anna , Alex)
    //generate a new real clone list
    val cloneNames = names.map{it.copy()}

    //modify first list
    cloneNames.get(0).n = "Another Anna clone"

    println(names.toList())
    println(cloneNames.toList())
}

[Person(n=Anna), Person(n=Alex)]
[Person(n=Another Anna clone), Person(n=Alex)]
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
  • 1
    Hey @Dam, What if the class is not a data class? How do I clone with different hashcode? – Paresh P. Oct 14 '20 at 22:03
  • it saves my day. alhamdulillah – Shihab Uddin Jan 21 '21 at 09:17
  • Would this do a **deep copy**? – IgorGanapolsky Feb 17 '21 at 15:40
  • 3
    @IgorGanapolsky This will only deep copy known class members. And even this answer has a flow. All objects in the `List` are "deep copied" but not the `List` reference itself. `List` still points to the same memory location, only its content has been changed. If you add another list to your class and forget to apply the same steps mentioned here to the new `List`, you'll still have a headache. So no, this is not a generic *deep copy* solution, just a solution (workaround) for specific use cases – Farid Feb 19 '21 at 09:14
  • it saved my life – Federico Sawady Sep 29 '21 at 00:03
  • Do I have to put `.copy()`? It works without the code. Why do I have to call `copy()` method? – Isaac Lee Dec 23 '21 at 08:47
  • `map` function does not copy the list – Egemen Hamutçu Feb 03 '23 at 15:47
10
var oldList: List<ClassA>?

val newList = oldList.map { it.copy() }
Community
  • 1
  • 1
Yasin Ege
  • 605
  • 4
  • 14
1

This is not related to kotlin, when you are adding the objects from the old list to the new one, it add the reference to them (no createing a new object ), whats mean it just copying the address in the memory to the new list.

To fix this problem you should create a new instance for each object. you can create a copy constructor, for example:

constructor(otherA: ClassA) {
    this.prop1 = otherA.prop1
    this.prop2 = otherA.prop2
    ...
} 

and then add them one by one to the new list:

list1.forEach { list2.add(Class(it)) }
Roi Amiel
  • 353
  • 1
  • 3
  • 18