通过序列化进行深度克隆时,通过引用克隆一些实例字段

时间:2016-09-03 11:09:17

标签: java serialization clone

我正在使用序列化深入克隆一个大型Java类,如this answer所示。在相应的问题中,我解释了为什么我需要以这种方式克隆,这突出了不同深度克隆技术的结果的重要区别,关于保留克隆中的共享引用,在我的情况下是必须的。换句话说,如果在原始的两个字段中指向同一个对象,则在深度克隆中,这些字段不应指向两个不同的新对象,而应指向同一个新对象。通过序列化进行深度克隆可以实现这一目标。

由于此技术所需的树中类的唯一更改是让所有类都实现Serializable,因此我不会在树的每个类中编写“clone”方法。所以我不是在每个类中编写代码来克隆它的每个字段。但是我仍然希望排除克隆过程中的某些字段,我通过将transient修饰符添加到我不想克隆的字段的声明中来实现。克隆中的这些字段为null

现在我有不同的需求。我需要能够说某个字段必须克隆,但不能克隆:只需复制引用;让克隆中的该字段指向与原始字段相同的对象。

所以我想知道如何使序列化通过简单地复制引用而不是序列化来克隆该特定字段 - 像对待其他字段一样对其进行反序列化。这是我的问题。

否则,我能想到的唯一解决方案是在树的每个类中实现“克隆”方法(不一定是Object.clone()),并且在每个“克隆”方法中明确地分配每个字段,使用序列化一些字段并复制其他字段的引用。但是由于要克隆有很多字段的类,这是很多工作,我也害怕以这种方式我将不再保留主对象树中的共享引用,因为我会分别克隆每个字段,因此如果树中的两个字段指向同一个对象,则在克隆每个字段时将无法知道这一事实,因此序列化不可能使它们指向同一个新对象。

1 个答案:

答案 0 :(得分:1)

我想在关于复制私有瞬态字段的评论中展示我提到的想法。在这里,我进一步开发了它,引入了一个吸气剂,使参考可以从物体中取出更清晰。请注意,getter是私有的,也就是说,它只能从类中调用,这对我们来说已经足够了。代码已编译。

public class MyClonable {

    private transient List<String> fieldRequiringShallowCopy;

    /** getter to be used by cloning */
    private List<String> getFieldRequiringShallowCopy() {
        return fieldRequiringShallowCopy;
    }

    /**
     * Call this method after cloning by serialization to copy transient field.
     * @param original The object that this object was cloned from.
     */
    public void finishClone(MyClonable original) {
        this.fieldRequiringShallowCopy = original.getFieldRequiringShallowCopy();
    }

}

编辑:要在评论中回答您的问题,如果需要浅拷贝的字段更深层地嵌套在您的大对象中,您需要从外部调用并委托给持有该字段的子对象:

public class BigClonable {

    private Part enclosedThing;

    private Part getEnclosedThing() {
        return enclosedThing;
    }

    /**
     * Call this method after cloning by serialization to copy transient field.
     * @param original The object that this object was cloned from.
     */
    public void finishClone(BigClonable original) {
        // delegate to part object
        enclosedThing.finishClone(original.getEnclosedThing());
    }

}

public class Part {

    private transient List<String> fieldRequiringShallowCopy;

    /** getter to be used by cloning */
    private List<String> getFieldRequiringShallowCopy() {
        return fieldRequiringShallowCopy;
    }

    public void finishClone(Part original) {
        this.fieldRequiringShallowCopy = original.getFieldRequiringShallowCopy();
    }

}

此技术可用于任何嵌套级别。你需要在每个级别都有一个委托方法,我的口味也是每个级别的私人getter(和/或setter)。