曾几何时有一堂课:
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 {
}
我应该如何克隆它?
答案 0 :(得分:10)
我认为目前的绿色答案很糟糕,为什么你会问?
哦顺便说一下序列化也很糟糕,你可能不得不在整个地方添加Serializable(这也让我哭了)。
那么解决方案是什么:
Java Deep-Cloning库 克隆库是一个小型的开源(apache许可证)java库,它深入克隆对象。对象不必实现Cloneable接口。实际上,这个库可以克隆任何java对象。如果您不希望修改缓存对象或者只是想要创建对象的深层副本,则可以在缓存实现中使用它。
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
上查看
答案 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
实例。