super.clone()操作在Derived Class中不起作用

时间:2012-10-25 09:01:07

标签: java inheritance clone cloneable

由于我的项目面临技术困难,因此提出了这个问题。

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

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

家长班:

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()方法引用类 - UnChangeableBaseClass类型,并且它不会覆盖Object clone()方法。我相信所有类都使用java.lang.Object class扩展,隐式protected Object clone()方法将继承到此父类。所以,我认为Derived Class中的这个方法会覆盖Parent / Object克隆方法。但是在运行时JVM搜索UnChangeableBaseClass中明确定义的克隆方法。希望我能以正确的方式解释而不会让你感到困惑。

我的问题如下:

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

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

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

4 个答案:

答案 0 :(得分:2)

  

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

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

  

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

我建议,即使您可以选择使用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方法,这个方法会   返回原始的字段副本。

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

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

答案 1 :(得分:2)

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

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()因为它没有标记为Cloneable。如果你不能改变父类,那么你必须自己制作一份副本。

答案 2 :(得分:1)

我正在使用java 1.7,我在运行OP给出的代码时没有遇到任何问题。 除非超类重写了克隆以抛出异常,否则我认为即使超类不声明自己是克隆的,这也应该有效。

我会注意到

public Object clone()

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

答案 3 :(得分:0)

正确的方法签名在

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

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

   internalClone((Cloneable) this);

因此,clone()内的Object方法只会在CloneNotSupportedException Cloneable clone()之前抛出protected

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

  1. Object方法在clone()课程中为child.clone(),因此您无法在课堂外调用public。例如Cloneable除非您覆盖它并进行访问Cloneable
  2. CloneNotSupportedException是标记界面,如果您没有标记类clone(),那么如果您调用super.clone方法
  3. ,您将获得super.clone
  4. 如果一个类只包含原始字段或对不可变对象的引用,那么通常情况是superclasses (except Object)返回的对象中的任何字段都不需要修改。
  5. 按照惯例,应该通过调用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}}就是这种情况。
  6. 以下代码工作正常

    {{1}}

    参考文献:

    1. Object#clone()
    2. Cloneable