12

从前有一堂课:

public class Scope<C extends Cloneable & Comparable<C>> implements Comparable<Scope<C>>, Cloneable, Serializable {

   private C starts;
   private C ends;
   ...

   @SuppressWarnings("unchecked")
   @Override
   public Object clone() {
       Scope<C> scope;
       try {
           scope = (Scope<C>) super.clone();
           scope.setStarts((C) starts.clone()); // The method clone() from the type Object is not visible
           scope.setEnds((C) ends.clone()); // The method clone() from the type Object is not visible
       } catch (CloneNotSupportedException e) {
           throw new RuntimeException("Clone not supported");
       }
       return scope;
   }
}

在对象中,我们有:

protected native Object clone() throws CloneNotSupportedException;

而Cloneable接口是:

public interface Cloneable { 
}

我应该如何克隆这个?

4

6 回答 6

12

解决方案

使用Java 深度克隆库。

克隆库是一个小型的开源(apache 许可证)java 库,它可以深度克隆对象。对象不必实现 Cloneable 接口。实际上,这个库可以克隆任何 java 对象。如果您不希望修改缓存的对象或想要创建对象的深层副本,则可以在缓存实现中使用它。

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

附录

以前的答案有以下缺点:

  • 它添加了很多代码
  • 它要求您列出要复制的所有字段并执行此操作
  • 使用时,这不适用于列表clone()clone()forHashMap注释:返回此实例的浅表副本HashMap:键和值本身未克隆,因此您最终手动执行。

序列化也很糟糕,因为它可能需要Serializable在任何地方添加。

于 2009-08-07T06:02:03.083 回答
5

这也是没人喜欢Cloneable的原因之一。Cloneable它应该是一个标记接口,但它基本上是无用的,因为你不能在没有反射的情况下克隆任意对象。

几乎唯一的方法是使用公共 clone()方法创建您自己的接口(不必将其称为“ clone()”)。这是另一个 StackOverflow 问题的示例

于 2009-04-29T19:51:48.470 回答
4

希望我已经解决了Java中的泛型克隆问题:

public class Generic<T> {
  private T data;

  public Generic() {
    // ...
  }

  @SuppressWarnings("unchecked")
  @Override
  public Object clone() {
    Generic<T> cloned = new Generic<T>();
    try {
      cloned.data = (T) data.getClass().getMethod("clone").invoke(data);
    } catch (Exception e) {
      // ...
    }
    return cloned;
  }
}
于 2013-02-11T08:27:50.107 回答
2

有点 OT,但你可以用这个来为自己节省很多未来的悲伤:

   catch (CloneNotSupportedException e) {
       throw new RuntimeException("Clone not supported", e);
   }

这样,当您获得堆栈跟踪时,您就知道是哪个对象导致了问题。

为了回答核心问题,您自己的接口实现了mmyers 编写的公共clone() 并要求 C 也扩展它。

于 2009-04-29T20:31:40.933 回答
1

作为一般评论,尽可能避免使用 Object.clone() 。如果您可以控制相关代码,请改为实现复制构造函数。有关信息,请参见此处

于 2009-04-29T20:44:31.340 回答
-1

如您所见,如果一个类试图实现Cloneable并且您想要一个深度克隆,那么您的所有组成对象都需要是不可变的、原始的,或者也需要是可克隆的。

通常,更好和更简单的方法是创建一个复制构造函数。

public class Scope<C extends Comparable<C>> implements Comparable<Scope<C>>, Serializable {
    private C starts;
    private C ends;
    public Scope(final Scope original) {
       starts = new C(original.starts);
       ends = new C(original.ends);
       // initialize all my other fields from "original"
    }
}

当然,您需要一个C能够处理多态性的复制构造函数。

如果您无法访问或无法将源代码修改为C,那么任何复制方法,无论采用何种方法,都将非常困难并且可能是不可能的。例如,无法复制enum实例。

于 2009-04-29T19:57:59.780 回答