[SalesForce] Object clone does not work as expected

I have an object (not SObject!) with a member of type List, when I clone the object and add something to the list, the original record will also be modified:

public class ThingToClone {
    public List<Integer> values = new List<Integer>();    
}

ThingToClone original = new ThingToClone();
ThingToClone clone = original.clone();
clone.values.add(1);

System.debug(LoggingLevel.ERROR, original);

results in

12:04:15:022 USER_DEBUG [5]|ERROR|ThingToClone:[values=(1)]

This is not what I expected, and I was not able to find any "Apex Object" documentation. Is there something like that? All I found was SObject related.

Edit:

To see if it creates a shadow object, I also tried to modify a class member, that was not part of the list. called it Integer anyNumber

ThingToClone original = new ThingToClone();
ThingToClone clone = original.clone();
clone.values.add(1);
clone.anyNumber = 2;
original.anyNumber = 3;

The new debug result is something really strange:

System.debug(LoggingLevel.ERROR, clone);
System.debug(LoggingLevel.ERROR, original);

USER_DEBUG [6]|ERROR|ThingToClone:[anyNumber=2, values=(1)]
USER_DEBUG [7]|ERROR|ThingToClone:[anyNumber=3, values=(1)]

So it's clearly not the same(shadow) object

Best Answer

I disagree and say it works as expected. My assumption is that Apex clone() uses Java's clone() internally. Java's clone() is a shallow clone, meaning the list in ThingToClone will just point to the original objects list.

As described here (http://howtodoinjava.com/core-java/cloning/a-guide-to-object-cloning-in-java/#deep_cloning):

By default, java cloning is ‘field by field copy’ i.e. as the Object class does not have idea about the structure of class on which clone() method will be invoked. So, JVM when called for cloning, do following things:

1) If the class has only primitive data type members then a completely new copy of the object will be created and the reference to the new object copy will be returned.

2) If the class contains members of any class type then only the object references to those members are copied and hence the member references in both the original object as well as the cloned object refer to the same object.

So I guess @IllusiveBrain is right in his comment, where he states that clone() copies primitive variables by value and non-primitive variables by reference. I'd expect this to be NO platform bug but intended behavior.

Related Topic