2

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

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

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

家长班:

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

我的问题如下:

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

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

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

4

4 回答 4

2

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

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

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

我建议,即使您可以选择使用clone方法来克隆对象,也不应该使用它。最好copy-constructor在派生类中使用 a ,并添加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());
}
于 2012-10-25T09:09:52.663 回答
2

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() 因为它没有被标记为可克隆。如果您无法更改父类,那么您必须自己制作一个副本。

于 2012-10-25T09:13:47.670 回答
1

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

我会注意到

public Object clone()

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

于 2012-10-25T09:26:00.463 回答
0

正确的方法签名如下

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

克隆是类中的Protected方法,Object因此您可以在类中访问它,并且如果您从它扩展。 super.clone()只需要从调用当前类对象的clone()方法的对象调用方法internalClonethis

   internalClone((Cloneable) this);

所以上面的clone()方法只有在调用它的实例不是Object时才会抛出CloneNotSupportedExceptionCloneable

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

  1. clone()方法protectedObject类内,所以你不能 clone()在类外调用。例如child.clone(),除非您覆盖它并进行访问public
  2. Cloneable是标记接口,如果你不标记类Cloneable,那么你会得到CloneNotSupportedException如果你调用clone()方法
  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. 对象#克隆()
  2. 可克隆
于 2012-10-25T09:12:01.057 回答