深克隆,同时保留对可变对象的共享引用 [英] Deep-cloning while preserving shared references to mutable objects

查看:101
本文介绍了深克隆,同时保留对可变对象的共享引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过在此类及其组成它的整个字段层次结构中实现 clone()来深化某个类的实例。在这些类中的 clone()实现中,我通过调用 clone()放在相应原始字段上( this )。然后,我只在主类上调用 clone()。我相信这是深度克隆的一种标准方法。

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.

但是表示如果原始字段 a b 引用的是同一对象X,则在深度克隆中它们将不引用同一对象(X的克隆);相反,它们将引用两个不同的X克隆。

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;
    }   

}


推荐答案

没有这种克隆操作的标准方法。另外,我还不知道有哪个库支持该功能。

There is no "standard" way of such a clone operation. Additionally, I am not aware of any library that supports that.

您真正要说的是从原始对象构建一对一映射(双射)。对象到克隆对象。

What your requirement really says, is to build a 1-to-1 mapping (a bijection) from original object to a cloned object.

一种技术是,一旦调用了clone方法,则首先通过克隆每个对象(如果不在地图中)来建立这样的层次结构。在您的根对象上。然后,在新的克隆层次结构中组装引用。

A technique would be to first build up such a hierarchy by cloning each object if it is not in the map, once the clone method is called on your root object. Afterwards, assemble the references in the new clone hierarchy.

该技术-顺便说一下-已经由Java中的序列化技术实现。让您的所有类都实现 Serializable ,然后将根对象写入 ObjectOutputStream 将其传递到 ObjectInputStream ,然后反序列化所有对象。序列化机制可以满足您的要求。

That technique - by the way - is already implemented by the serialization technique in Java. Have all your classes implement Serializable, then write the root object to an ObjectOutputStream, pipe it to an ObjectInputStream, and then deserialize all objects. The serializing mechanism takes care of your requirement.

这篇关于深克隆,同时保留对可变对象的共享引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆