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 {
private 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 {
private Apple apple;
private Pencil pencil;
private 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?
String
andInteger
.