用泛型克隆

时间:2009-04-29 19:48:06

标签: java clone

曾几何时有一堂课:

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 { 
}

我应该如何克隆它?

6 个答案:

答案 0 :(得分:10)

我认为目前的绿色答案很糟糕,为什么你会问?

  • 它增加了很多代码
  • 要求您列出要复制的所有字段并执行此操作
  • 使用clone()时,这不适用于列表 (这就是HashMap的clone()所说的:返回这个HashMap实例的浅表副本:键和值本身没有被克隆。)所以你最终手动完成它(这让我哭了)

哦顺便说一下序列化也很糟糕,你可能不得不在整个地方添加Serializable(这也让我哭了)。

那么解决方案是什么:

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

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

http://code.google.com/p/cloning/

上查看

答案 1 :(得分:4)

这是no one likes Cloneable的原因之一。它应该是一个标记界面,但它基本上没用,因为你不能在没有反射的情况下克隆任意Cloneable个对象。

实现此目的的唯一方法是使用 public clone()方法创建自己的界面(不必将其称为“clone()”) 。来自另一个StackOverflow问题的Here's an example

答案 2 :(得分:3)

希望我已经解决了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;
  }
}

答案 3 :(得分:2)

稍微过了一点,但你可以用这个来拯救自己很多未来的悲痛:

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

因此,当您获得堆栈跟踪时,您知道哪个对象导致了问题。

要回答核心问题,你自己的界面实现了公共克隆()作为mmyers编写并要求C也扩展它。

答案 4 :(得分:1)

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

答案 5 :(得分:-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实例。