【问题标题】:super.clone() Queries?super.clone() 查询?
【发布时间】:2011-12-28 11:34:18
【问题描述】:

请澄清以下问题。

  1. super.clone() 是执行深拷贝还是浅拷贝?
  2. 在下面的例子中,为什么我们不需要类CompositeObjCloneMe作为可克隆的?尝试克隆 CloneMe 对象时不会克隆 cObj 吗? 注意:即使将 CompositeObjCloneMe 设为可克隆也不会对输出产生任何影响。
  3. 由于程序正在设置类的原始值(setCObjValue = 100),为什么输出的行为类似于浅拷贝(不是深拷贝)? (原始字段被深度复制)
  4. 不可变对象&&原语本质上是被深度复制的吗?

    class CloneMe implements Cloneable {
        private CompositeObjCloneMe cObj;
    
        public CloneMe() {
            cObj = new CompositeObjCloneMe();
          }
    
        public void setCObjValue(int myOwnDt) {
            this.cObj.setObj(myOwnDt);
        }
        public int getCObjValue() {
            return this.cObj.getObj();
        }
        //Clone
        public Object clone() throws CloneNotSupportedException {
        return super.clone();
        }
    }
    
    class CompositeObjCloneMe {//implements Cloneable{
        private int value = 20;
        public void setObj(int i){
            value = i;
        }
        public int getObj(){
            return value;
        }
    //  public Object clone() throws CloneNotSupportedException{
    //      return super.clone();
    //  }
    }
    
    
    public class CloneTest {
        public static void main(String arg[]) {
            CloneMe realObj = new CloneMe();
            try {
                CloneMe cloneObj = (CloneMe) realObj.clone();
                realObj.setCObjValue(100);
                System.out.println(realObj.getCObjValue()  + "   " + cloneObj.getCObjValue());
            } catch (CloneNotSupportedException cnse) {
                System.out.println("Cloneable should be implemented. " + cnse);
            }
        }
    }
    

输出:100 100

【问题讨论】:

    标签: java


    【解决方案1】:

    1) javadoc 救援:

    [...] 因此,此方法执行此对象的“浅拷贝”,而不是 “深拷贝”操作。

    2) 因为 clone 不会递归调用 clone。这是一个浅克隆。它只是创建一个具有与原始对象相同引用的新对象,以及原始字段的副本。

    3) 我不明白你的意思。原始数据没有被深度复制。他们没有引用任何东西,所以没有什么可以复制的。

    【讨论】:

    • 非常感谢。第2点消除了我所有的疑虑。我混淆了像序列化这样的递归操作。
    • 是否可以使用 super.clone() 进行深度复制?
    • 没有。您必须调用它,然后递归地自己显式地克隆所有引用的对象(这并不总是可能的)。复制构造函数通常优于克隆。
    • 非常感谢。我想我可以在需要深度复制时继续使用复制构造函数。
    【解决方案2】:

    JB Nizet 已经回答了第一个和第二个问题。

    对于您的第三个问题,您的 realObjcloneObj 都指的是同一个 CompositeObjCloneMe 实例。当您克隆真实对象时,克隆对象的CompositeObjCloneMe 字段cObj 将与realObj 中的实例相同。因此,通过调用realObj.setCObjValue(100); 更改realObjcObj 也会影响cloneObj

    所以输出正是预期的。

    注意:您可以通过使用调试器并查看realObjcloneObj 的字段来轻松验证这一点

    如果您想进行深度克隆,则应调用 super.clone 并同时克隆非原始字段。例如

    public Object clone() throws CloneNotSupportedException {
      CloneMe clone = (CloneMe)super.clone();
      clone.cObj = ...;//make a clone, a new instance, ...
      return clone;
    }
    

    重要的是调用super.clone 来创建您将返回的对象,而不是简单地调用CloneMe clone = new CloneMe();。否则,如果子类也想实现克隆,则必须复制类中的所有逻辑。

    一些额外的文档:WikipediaCodeguru

    【讨论】:

    • 谢谢。我得到了它。是否可以使用 super.clone() 进行深度复制?
    猜你喜欢
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多