我通过在此类及其组成的整个层次结构中实现clone()
来深度克隆某个类的实例。在我放入这些类的clone()
实现中,我通过在原始(clone()
)的相应字段上调用this
来分配新实例的每个字段。然后我只需在主类上调用clone()
。我相信这是一种非常标准的深度克隆方式。
下面是一个小的可运行的例子。我得到的克隆是一个真正的深层复制,其中每个字段和子字段中包含的对象都是新对象,与原始实例中的对象相同。
但这意味着如果原始字段a
和b
引用同一个对象X,则在深度克隆中它们不会引用同一个对象(X的克隆);相反,他们将引用X的两个不同克隆。
所以我想深度克隆一个对象,深度克隆整个层次结构中的所有字段,但如果层次结构在多个字段中包含相同的引用,则只应将其中一个字段深度克隆到一个新的对象;其他字段只会引用这个新对象。
一个简单的解决方案看起来不像是一个问题,但是我想知道是否存在某种技术,或者某些工具或库可以做到这一点。
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;
}
}
答案 0 :(得分:2)
这种克隆操作没有“标准”方式。另外,我不知道任何支持它的库。
您的要求实际上是说,从原始对象到克隆对象构建一对一映射(双射)。
一种方法是,一旦在根对象上调用clone方法,首先通过克隆每个对象(如果它不在地图中)来构建这样的层次结构。然后,组合新克隆层次结构中的引用。
顺便说一下,这种技术已经通过Java中的序列化技术实现了。让所有类实现Serializable
,然后将根对象写入ObjectOutputStream
,pipe it to an ObjectInputStream
,然后反序列化所有对象。序列化机制可以满足您的要求。
答案 1 :(得分:1)
简短回答:不可能。
答案很长:
这就是深度克隆的事情:你没有很好的机会。你看,最终,克隆是由JVM完成的(或多或少:黑魔法)。
现在你问:我怎样才能使用#34;标准"克隆方式;但不知何故,确保克隆某些"根对象X"的整个过程。将使用某种"缓存"机制。我注意到任何现有的机制来指示JVM这样做。
长话短说:我认为你必须研究其他选择;喜欢序列化为一些合理的格式;然后使用该输出。
最后引用了一个伟大的answer:
听起来你认为克隆是一个好主意(与使用复制构造函数,工厂或其等价物相比)。
并继续:
现在,更重要的是,克隆是一个坏主意。