26

this is my code:

var header1: Record? = null
var header2: Record? = null

header2 = header1
header2.name = "new_name"

but header1.name changes too!

SadeQ digitALLife
  • 1,403
  • 4
  • 16
  • 22
  • the correct answer is using copy() but I suggest you not to use var at all and instead use val with the correct constructor for header. If you need to create 2 objects almost identical apart one field or two, just create a function fun buildHeader(name: String): Record {...} val header1 = buildHeader("name1") val header2 = buildHeader("name2") – Uberto May 08 '18 at 19:31

4 Answers4

45

You are just assigning the same object (same chunk of memory) to another variable. You need to somehow create a new instance and set all fields.

header2 = Record()
header2.name = header1.name

However in Kotlin, if the Record class was Data class, Kotlin would create a copy method for you.

data class Record(val name: String, ...)
...
header2 = header1.copy()

And copy method allows you to override the fields you need to override.

header2 = header1.copy(name = "new_name")
Mohsen
  • 1,246
  • 9
  • 22
Josef Adamcik
  • 5,620
  • 3
  • 36
  • 42
  • But how can I do it again? How can I copy all params from one object to another immutable object if it is already instantiated? – Ruslan Berozov May 11 '19 at 14:57
  • @RuslanBerozov you cannot, immutable means you cannot change the instance. Therefore you cannot copy values to the already instantiated object in such case. But it's most likely you don't need to. – Josef Adamcik May 11 '19 at 18:53
  • @jocef-adamcik there are some situations when I need to do that. For example - I need to update item in "currentList" in PagedListAdapter. I did it with custom function in data class of item. – Ruslan Berozov May 11 '19 at 23:53
  • @RuslanBerozov If you really need to, you have to use mutable objects. Usually, I would aim to use immutable objects and replace the instance in the list. But I have no experience with PageListAdapter in particular and I am not sure what are all the limitations there. Also, your situation would be most likely even more specific. I don't think it is possible and/or makes sense to try to figure it out here in comments. Consider making a SO question for your situation. – Josef Adamcik May 13 '19 at 09:15
3

If your Class is not a Data Class and your project has Gson and you want to copy the whole object ( probably edit after getting it ), Then if all those conditions are true then this is a solution. This is also a DeepCopy. ( For a data Class you can use the function copy()).

Then if you are using Gson in your project. Add the function copy():

class YourClass () {

// Your class other stuffs here

  fun copy(): YourClass { //Get another instance of YourClass with the values like this!
      val json = Gson().toJson(this)
      return Gson().fromJson(json, YourClass::class.java)
  }
}

If you want to install Gson then get the latest version here.

Xenolion
  • 12,035
  • 7
  • 33
  • 48
  • This seems very hacky to me. Are there any downsides to using this? – Alan Nelson Dec 22 '20 at 21:36
  • 1
    Its more like Gson was made to copy and retrieve classes, so you make use of that feature. – Xenolion Dec 24 '20 at 06:20
  • 1
    @AlanNelson This would only work in cases where the object in question can be serialized and deserialized using Gson. That breaks down with [collections](https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Limitations), for instance. Also, Gson would not know when to stop, so it would perform a deep clone, and it would clone even state that you wanted to be shared between the source and copy objects. – Rafael Chaves Feb 18 '21 at 12:29
1

You got 2 options use the copy method if the second object needs to be exactly the same or some of a fields needs to be changed.

val alex = User(name = "Alex", age = 1)
val olderAlex = alex.copy(age = 2)

or Kotlin got the great syntax of constructing object I mean, e.g.

createSomeObject(obj = ObjInput(name = objName,
                    password = UUID.randomUUID().toString()
                    type = listOf(TYPE)))

In fact, It seems to be easier in your case use first one but good to know about the second way to resolve this task.

Xenolion
  • 12,035
  • 7
  • 33
  • 48
0

You have to create a new instance of the variable and initialize every field. If you just do header2 = header1 you are also passing the reference of header1 to header2.

Example (Java):

public Record(Record record) {
    this.name = record.name;
}

Then call it as: header2 = new Record(header1);

See: Is Java "pass-by-reference" or "pass-by-value"?

Lucas Cabrales
  • 2,073
  • 1
  • 12
  • 21