I am deep-cloning instances of a certain class by implementing clone()
in this class and in its whole hierarchy of fields that compose it. In the clone()
implementations that I put in these classes, I assign each field of the new instance by calling clone()
on the corresponding field of the original (this
). Then I just call clone()
on the main class. I believe this is quite a standard way of deep-cloning.
Below there is a small runnable example. The clone I get is a real deep copy, where the objects contained in each field and subfield are all new objects, identical to their counterparts from the original instance.
But this means that if in the original the fields a
and b
were referencing the same object X, in the deep clone they will not be referencing the same object (clone of X); instead they will be referencing two different clones of X.
So I would like to deep-clone an object by deep-cloning all its fields in its whole hierarchy, but if the hierarchy contains the same reference in more than one field, only one of these fields should be deep-cloned into a new object; the other fields will just reference this new object.
It doesn't look like a problem with an easy solution, however I'm wondering if some technique exists for that, or maybe some tool or library that does that.
TestClone.java
public class TestClone {
public static void main(String[] args) throws CloneNotSupportedException {
// Create the object to share :
SharedObject shared = new SharedObject(1);
// Create the object to clone, which will own two Holder instances
// both holding a reference to *the same* object :
MainObject original = new MainObject(new Holder(shared), new Holder(shared));
// Show that both holders hold a reference to the same object :
System.out.println("Original holder1 holds " + original.holder1.field.hashCode());
System.out.println("Original holder2 holds " + original.holder2.field.hashCode());
// Deep-clone the main object :
MainObject cloned = (MainObject) original.clone();
// Show that the two cloned holders now hold a reference to *different* cloned objects :
System.err.println("Cloned holder1 holds " + cloned.holder1.field.hashCode());
System.err.println("Cloned holder2 holds " + cloned.holder2.field.hashCode());
// How to clone so that they will hold a reference to *the same* cloned object ?
}
}
SharedObject.java
public class SharedObject implements Cloneable {
public int n;
public SharedObject(int n) {
this.n = n;
}
@Override
protected Object clone() throws CloneNotSupportedException {
SharedObject clone = (SharedObject) super.clone();
clone.n = this.n;
return clone;
}
}
Holder.java
public class Holder implements Cloneable {
public SharedObject field;
public Holder(SharedObject field) {
this.field = field;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Holder clone = (Holder) super.clone();
clone.field = (SharedObject) this.field.clone();
return clone;
}
}
MainObject.java
public class MainObject implements Cloneable {
public Holder holder1;
public Holder holder2;
public MainObject(Holder holder1, Holder holder2) {
this.holder1 = holder1;
this.holder2 = holder2;
}
@Override
protected Object clone() throws CloneNotSupportedException {
MainObject clone = (MainObject) super.clone();
clone.holder1 = (Holder) this.holder1.clone();
clone.holder2 = (Holder) this.holder2.clone();
return clone;
}
}