【问题标题】:super.clone() operation not works in Derived Classsuper.clone() 操作在派生类中不起作用
【发布时间】:2012-10-15 10:19:01
【问题描述】:

这是因为我的项目面临技术困难而提出的。

问题: 我需要克隆一个类的对象,它从第三方库类(我们无权修改其内容)扩展属性(继承)

让我用下面的例子来解释:

父类:

public class UnChangeableBaseClass {

  //fields and Methods

}

儿童班:

class DerivedLocalClass extends UnChangeableBaseClass implements Cloneable {

   // local fields and methods


   public Object clone(){

      Object clonedObj= null;

      try{
       clonedObj = super.clone();
      }
      catch(CloneNotSupportedException e){
        //log exceptions
      }

   }

}

当我尝试这样做时,super.clone() 方法指的是 Class - UnChangeableBaseClass 类型,它不会覆盖 Object clone() 方法。我相信所有的类都是用java.lang.Object class 扩展的,隐含的protected Object clone() 方法将被继承到这个父类。所以,我认为派生类中的这个方法会覆盖父/对象克隆方法。但是在运行时 JVM 搜索在UnChangeableBaseClass 中明确定义的克隆方法。希望我以正确的方式解释,不会让您感到困惑。

我的问题如下:

  1. 在这种无法添加任何方法的典型情况下,如何实现克隆方法
    在父类中有super.clone()调用对象克隆方法。

  2. 如果上述情况不可行,是否有任何其他方法可以克隆派生类
    对象(通过考虑上述场景中的所有限制)

  3. 最后,只是为了了解这种 JVM 行为的原因(如上所述)。

【问题讨论】:

    标签: java inheritance clone cloneable


    【解决方案1】:

    JVM 克隆通过使用标记接口 Cloneable 来工作,而不是寻找 Object.clone()。的确,所有 Java 类都将继承 clone 方法,但根据 javadoc for Cloneable

    A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.
    

    在你的情况下你不能做 super.clone() 因为它没有被标记为可克隆。如果您无法更改父类,则必须自己制作一个副本。

    【讨论】:

      【解决方案2】:

      如何在这种典型情况下实现克隆方法,我们不能 在父类中添加任何方法以使 super.clone() 调用 Object 克隆方法。

      好吧,因为clone 方法是Object 类中的受保护方法,所以它也可以在您的超类UnChangeableBaseClass 中访问,因为它是从Object 类扩展而来的。所以,基本上你可以使用super.clone(),从你的基类DerivedLocalClass访问clone方法。

      如果上述情况不可能,有没有其他方法可以克隆 派生类对象(通过考虑上述所有限制 情景)

      我建议,即使您可以选择使用clone 方法来克隆对象,您也不应该使用它。最好在派生类中使用copy-constructor,并在基类构造函数中添加super() 调用。

      另外,参见Effective Java - Item#11 - Override clone judiciously,这表明clone 方法已损坏。

      在这篇文章中:-Josh Bloch on Design - Copy Constructor versus Cloning,你想看Bloch的第一段:-

      如果你读过我书中关于克隆的内容,尤其是如果你 字里行间,你会知道我认为克隆是深刻的 破碎的。有一些设计缺陷,其中最大的是 Cloneable 接口没有克隆方法。这意味着它 根本行不通:制作可克隆的东西并没有说明什么 关于你可以用它做什么。相反,它说明了什么 它可以在内部进行。它说如果通过调用 super.clone 反复调用 Object 的 clone 方法,这个方法将 返回原件的现场副本。

      所以,结论是,你可以在你的DerivedLocalClass 中有一个copy constructor,它将返回调用对象的副本,如下所示:-

      public DerivedLocalClass(DerivedLocalClass obj) {
          this.setVar(obj.getVar());
      }
      

      【讨论】:

      • 因为受到保护,所以可以在 super 中访问。
      • @RohitJain 我会再给一个 +1 作为参考,但 Stack Overflow 不让我 :)
      • @AmitD。哦耶。我忘记了。废话:(
      【解决方案3】:

      我使用的是 java 1.7,运行 OP 给出的代码没有任何问题。 除非超类已重写克隆以引发异常,否则我认为即使超类未声明自己可克隆,这也应该有效。

      我会注意到

      public Object clone()
      

      没有覆盖克隆方法,它缺少 throws 子句。

      【讨论】:

      • 它的压倒一切。我们当然可以减少对覆盖方法的限制。但这只需要在方法中处理Exception即可。
      【解决方案4】:

      正确的方法签名如下

      @Override
      public Object clone() throws CloneNotSupportedException {
          return super.clone();
      }
      

      Clone 是 Object 类中的 Protected 方法,因此您可以在类内部访问它,如果您从它扩展。 super.clone() 只需要从对象调用clone() 方法,该对象调用this 上的方法internalClone,这是当前类对象。

         internalClone((Cloneable) this);
      

      所以上面的clone()方法在Object中只会抛出CloneNotSupportedException,如果它被调用的实例不是Cloneable

      我看到一些关于克隆方法的误解

      1. clone() 方法是 protectedObject 类内,因此您不能在类外调用 clone()。例如child.clone() 除非您覆盖它并进行访问 public
      2. Cloneable 是标记接口,如果你不标记类Cloneable,那么如果你调用clone() 方法,你会得到CloneNotSupportedException
      3. 如果一个类只包含原始字段或对不可变对象的引用,那么通常情况下super.clone返回的对象中不需要修改任何字段。
      4. 按照约定,返回的对象应该通过调用super.clone来获取。如果一个类及其所有superclasses (except Object) 遵守这个约定,那么x.clone().getClass() == x.getClass() 就是这种情况。

      所以下面的代码可以正常工作

      public  class Child extends UnChangeableBaseClass
              implements
                  Cloneable {
      
          int index = 0;
      
          public Child(int index) {
      
              this.index = 10;
          }
          @Override
          public Object clone() throws CloneNotSupportedException {
              return super.clone();
          }
      
      }
      

      参考资料:

      1. Object#clone()
      2. Cloneable

      【讨论】:

      • 你说得对!,我的代码实现过程中出现了一些误解,克隆操作很好,同时不需要使用Object中定义的throws,我们也可以使用try/在 Override 中捕获实现。
      猜你喜欢
      • 2011-07-22
      • 2011-11-15
      • 2014-07-09
      • 1970-01-01
      • 2017-01-29
      • 2020-10-14
      • 1970-01-01
      • 2012-07-20
      • 1970-01-01
      相关资源
      最近更新 更多