このクラスおよびそれを構成するフィールドの階層全体にclone()
を実装することにより、特定のクラスのインスタンスをディープクローンします。これらのクラスに実装したclone()
の実装では、元の対応するフィールド(this
)にclone()
を呼び出して、新しいインスタンスの各フィールドを割り当てます。それからメインクラスでclone()
と呼んでいます。私はこれがディープクローニングの標準的な方法だと信じています。変更可能なオブジェクトへの共有参照を保持している間のディープクローン
以下に小さな実行可能な例があります。私が得たクローンは、実際のディープコピーです。各フィールドとサブフィールドに含まれるオブジェクトはすべて元のインスタンスのものと同じ新しいオブジェクトです。
しかし、元のフィールドa
とb
が同じオブジェクトXを参照していた場合、ディープクローンでは同じオブジェクト(Xのクローン)を参照しません。代わりに、それらはXの2つの異なるクローンを参照するでしょう。
オブジェクト全体を階層全体にディープクローンしてオブジェクトをディープクローンしたいのですが、階層に複数のフィールドで同じ参照が含まれている場合これらのフィールドの1つだけを新しいオブジェクトに深くクローンする必要があります。他のフィールドはこの新しいオブジェクトを参照するだけです。
簡単な解決策では問題に見えませんが、そのためのテクニックがあるのか、それを行うツールやライブラリがあるのか疑問です。
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;
}
}
'SharedObject'、' Holder'と 'MainObject'がすべて' Serializable'を実装するようにテストコードを修正しました。 'clone()'実装をすべて削除し、 'TestClone'で' SerializationUtils.clone (メインオブジェクト) '私がそれを実行すると、クローン内の2つの「所有者」が同じ_cloned_ 'SharedObject'インスタンスへの参照を保持するようになりました。正確に私が必要としたもの。だから、この解決策で私は正しい方向に進んでいるようです。これを実際のコードに適用して、クローンするクラスはもちろんより大きく複雑になります。私はいくつかの問題に遭遇するかどうかを見ていきます。 – SantiBailors
あなたを助けてうれしいです。 – Seelenvirtuose
私はあなたのソリューションを実際のコードで実装しました。ありがたいことですが、他のテクニックと違って、これは深くクローンするだけでなく、共有リファレンスもクローンで共有されます。私はシリアライゼーションについて読んだことがあり、特に 'SerializationUtils.clone'はクローニングの選択肢でしたが、私は驚くべきことに他のクローニング技術とのこの重要な違いについては言及していませんでした。 – SantiBailors