我在Java上实现了克隆()的快速谷歌,发现:http: //www.javapractices.com/topic/TopicAction.do?Id = 71
它有以下评论:
复制构造函数和静态工厂方法提供了克隆的替代方法,并且更容易实现.
我想做的就是做一份深刻的副本.实现clone()似乎很有意义,但这篇谷歌排名很高的文章让我有点害怕.
以下是我注意到的问题:
这是一些无法编译的伪代码.
public class MyClass<T>{
..
public void copyData(T data){
T copy=new T(data);//This isn't going to work.
}
..
}
Run Code Online (Sandbox Code Playgroud)
示例1:在泛型类中使用复制构造函数.
拥有可重用代码的接口非常好.
public class MyClass<T>{
..
public void copyData(T data){
T copy=data.clone();//Throws an exception if the input was not cloneable
}
..
}
Run Code Online (Sandbox Code Playgroud)
示例2:在泛型类中使用clone().
我注意到克隆不是静态方法,但是不是仍然需要制作所有受保护字段的深层副本吗?在实现clone()时,在非可克隆子类中抛出异常的额外工作对我来说似乎微不足道.
我错过了什么吗?任何见解将不胜感激.
Yis*_*hai 52
基本上,克隆被打破了.什么都不会轻易与泛型一起使用.如果你有这样的东西(缩短以获得重点):
public class SomeClass<T extends Copyable> {
public T copy(T object) {
return (T) object.copy();
}
}
interface Copyable {
Copyable copy();
}
Run Code Online (Sandbox Code Playgroud)
然后使用编译器警告您可以完成工作.因为泛型在运行时被擦除,所以执行复制的东西会在其中生成编译器警告生成强制转换.在这种情况下,这是不可避免的..在某些情况下可以避免(谢谢,kb304),但并非总体而言.考虑必须支持子类或实现接口的未知类的情况(例如,您正在迭代不一定生成相同类的可复制副本集合).
aka*_*okd 25
还有Builder模式.有关详细信息,请参阅Effective Java
我不明白你的评价.在复制构造函数中,您完全了解类型,为什么需要使用泛型?
public class C {
public int value;
public C() { }
public C(C other) {
value = other.value;
}
}
Run Code Online (Sandbox Code Playgroud)
最近这里也有类似的问题.
public class G<T> {
public T value;
public G() { }
public G(G<? extends T> other) {
value = other.value;
}
}
Run Code Online (Sandbox Code Playgroud)
一个可运行的样本:
public class GenTest {
public interface Copyable<T> {
T copy();
}
public static <T extends Copyable<T>> T copy(T object) {
return object.copy();
}
public static class G<T> implements Copyable<G<T>> {
public T value;
public G() {
}
public G(G<? extends T> other) {
value = other.value;
}
@Override
public G<T> copy() {
return new G<T>(this);
}
}
public static void main(String[] args) {
G<Integer> g = new G<Integer>();
g.value = 1;
G<Integer> f = g.copy();
g.value = 2;
G<Integer> h = copy(g);
g.value = 3;
System.out.printf("f: %s%n", f.value);
System.out.printf("g: %s%n", g.value);
System.out.printf("h: %s%n", h.value);
}
}
Run Code Online (Sandbox Code Playgroud)
Java没有与C++相同的复制构造函数.
你可以有一个构造函数,它接受一个与参数类型相同的对象,但很少有类支持这个.(少于支持克隆的数量)
对于通用克隆,我有一个辅助方法,它创建一个类的新实例,并使用反射复制原始字段(浅拷贝)(实际上像反射但更快)
对于深层复制,一种简单的方法是序列化对象并对其进行反序列化.
顺便说一句:我的建议是使用不可变对象,然后你就不需要克隆它们了.;)
以下是许多开发人员不使用的一些缺点Object.clone()
Object.clone()方法需要我们在代码中添加大量语法,例如实现Cloneable接口、定义clone()方法和句柄CloneNotSupportedException,最后调用Object.clone()并强制转换为我们的对象。Cloneable接口缺少clone()方法,它是一个标记接口,并且其中没有任何方法,并且我们仍然需要实现它只是为了告诉 JVM 我们可以对clone()我们的对象执行。Object.clone()受到保护,因此我们必须提供我们自己的clone()间接调用Object.clone()。Object.clone()它不会调用任何构造函数。clone()如果我们在子类中编写方法,例如Person,那么它的所有超类都应该clone()在其中定义方法或从另一个父类继承它,否则super.clone()链将失败。Object.clone()仅支持浅复制,因此新克隆对象的引用字段仍将保留原始对象的字段所持有的对象。为了克服这个问题,我们需要clone()在每个类中实现 who\xe2\x80\x99s 引用我们的类所持有的,然后在我们的clone()方法中单独克隆它们,如下例所示。Object.clone()因为 Final 字段只能通过构造函数更改。在我们的例子中,如果我们希望每个Person对象的 id 都是唯一的,那么如果我们使用,我们将得到重复的对象,Object.clone()因为Object.clone()不会调用构造函数,并且最终id字段可以\xe2\x80\x99t 修改Person.clone().复制构造函数比Object.clone()因为它们
我认为Yishai的答案可以改进,所以我们不能用以下代码发出警告:
public class SomeClass<T extends Copyable<T>> {
public T copy(T object) {
return object.copy();
}
}
interface Copyable<T> {
T copy();
}
Run Code Online (Sandbox Code Playgroud)
这样一个需要实现Copyable接口的类必须是这样的:
public class MyClass implements Copyable<MyClass> {
@Override
public MyClass copy() {
// copy implementation
...
}
}
Run Code Online (Sandbox Code Playgroud)