clone() vs copy constructor vs factory method?

2022-08-31 12:09:11

我在Java中实现clone()的快速谷歌上发现了: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.    
   }
   ..
}

示例 1:在泛型类中使用复制构造函数。

工厂方法没有标准名称。

拥有一个可重用代码的接口真是太好了。

public class MyClass<T>{
    ..
    public void copyData(T data){
        T copy=data.clone();//Throws an exception if the input was not cloneable
    }
    ..
}

示例 2:在泛型类中使用 clone()。

我注意到克隆不是一个静态方法,但是是否仍然需要制作所有受保护字段的深度副本?在实现 clone() 时,在不可克隆的子类中抛出异常的额外工作对我来说似乎微不足道。

我错过了什么吗?任何见解将不胜感激。


答案 1

基本上,克隆已损坏。没有什么可以轻易地使用泛型。如果你有这样的东西(缩短以表达观点):

public class SomeClass<T extends Copyable> {


    public T copy(T object) {
        return (T) object.copy();
    }
}

interface Copyable {
    Copyable copy();
}

然后,使用编译器警告即可完成工作。由于泛型在运行时被擦除,因此执行复制操作的内容将具有编译器警告,并在其中生成强制转换。在这种情况下,这是不可避免的。在某些情况下是可以避免的(谢谢,kb304),但不是全部。考虑这样一种情况,您必须支持实现接口的子类或未知类(例如,您正在迭代一组不一定生成相同类的可复制对象)。


答案 2

还有生成器模式。有关详细信息,请参阅有效的 Java。

我不明白你的评价。在复制构造函数中,您完全了解类型,为什么需要使用泛型?

public class C {
   public int value;
   public C() { }
   public C(C other) {
     value = other.value;
   }
}

最近这里也有一个类似的问题。

public class G<T> {
   public T value;
   public G() { }
   public G(G<? extends T> other) {
     value = other.value;
   }
}

可运行的示例:

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);
    }
}