How to safely copy an object?
- by Prog
This question is going to be a little long. Please bear with me.
Something that happened in a project of mine made me think about how to safely copy objects. I'll present the situation I had and then ask a question.
There was a class SomeClass:
class SomeClass{
Thing[] things;
public SomeClass(Thing[] things){
this.things = things;
}
// irrelevant stuff omitted
public SomeClass copy(){
return new SomeClass(things);
}
}
There was another class Processor that takes SomeClass objects, copies them (via someClassInstance.copy()), manipulates the copy's state, and returns the copy. Here it is:
class Processor{
public SomeClass processObject(SomeClass object){
SomeClass copy = object.copy();
manipulateTheCopy(copy);
return copy;
}
// irrelevant stuff omitted
}
I ran this, and it had bugs. I looked into these bugs, and it turned out that the manipulations Processor does on copy actually affect not only the copy, but also the original SomeClass object that was passed into processObject.
I found out that it was because the original and the copy shared state - because the original passed it's field things into the copy when creating it.
This made me realize that copying objects is harder than simply instantiating them with the same fields as the original.
For the two objects to be completely disconnected, without any shared state, each of the fields passed to the copy also has to be copied. And if that object contains other objects - they have to be copied too. And so on.
So basically, in order to be able to actually copy an object, each class in the system must have a copy() method, that also invokes copy() on all of it's fields, and so on.
So for example, for copy() in SomeClass to work, it needs to look like this:
public SomeClass copy(){
Thing[] copyThings = new Thing[things.length];
for(int i=0; i<things.length; i++)
copyThings[i] = things[i].copy();
return new SomeClass(copyThings);
}
And if Thing has object fields of it's own, than it's own copy() method must be appropriate:
class Thing{
Apple apple;
Pencil pencil;
int number;
public Thing(Apple apple, Pencil pencil, int number){
this.apple = apple;
this.pencil = pencil;
this.number = number;
}
public Thing copy(){
// 'number' is a primitve.
return new Thing(apple.getCopy(), pencil.getCopy(), number);
}
}
And so on.
Of course, instead of all classes having a copy() method, the copying mechanism can happen in all of the getters and the constructors of classes (unless places where it isn't suitable, for example when the field points to an external object, not to an object that 'is part' of this object).
Still, that means that in order to be able to safely copy an object - most classes would have to have copying mechanisms in their getters.
My question is divided into two parts:
How frequently do you need to get a copy of an object? Is this a regular issue?
Is the technique described common and/or reasonable? Or is there a better way to make safe copies of objects?
Or is there an easier way to safely copy objects, without them sharing any state?