Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 克隆()vs复制构造函数vs工厂方法?_Java_Clone - Fatal编程技术网

Java 克隆()vs复制构造函数vs工厂方法?

Java 克隆()vs复制构造函数vs工厂方法?,java,clone,Java,Clone,我在google上用Java快速实现了clone(),发现: 它有以下评论: 复制构造函数和静态工厂方法提供了克隆的替代方法,并且更易于实现 我只想做一份深度拷贝。实现clone()似乎很有意义,但这篇谷歌排名很高的文章让我有点害怕 以下是我注意到的问题: 复制构造函数不使用泛型。 这里有一些不会编译的伪代码 public class MyClass<T>{ .. public void copyData(T data){ T copy=new T(dat

我在google上用Java快速实现了clone(),发现:

它有以下评论:

复制构造函数和静态工厂方法提供了克隆的替代方法,并且更易于实现

我只想做一份深度拷贝。实现clone()似乎很有意义,但这篇谷歌排名很高的文章让我有点害怕

以下是我注意到的问题:

复制构造函数不使用泛型。 这里有一些不会编译的伪代码

public class MyClass<T>{
   ..
   public void copyData(T data){
       T copy=new T(data);//This isn't going to work.    
   }
   ..
}
公共类MyClass{
..
公共无效复制数据(T数据){
T copy=newt(数据);//这行不通。
}
..
}
示例1:在泛型类中使用复制构造函数

工厂方法没有标准名称。 有一个可重用代码的接口非常好

public class MyClass<T>{
    ..
    public void copyData(T data){
        T copy=data.clone();//Throws an exception if the input was not cloneable
    }
    ..
}
公共类MyClass{
..
公共无效复制数据(T数据){
T copy=data.clone();//如果输入不可克隆,则引发异常
}
..
}
示例2:在泛型类中使用clone()

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


我错过什么了吗?任何见解都会被理解。

< P> java没有复制C++的相同的构造函数。

您可以有一个构造函数,它将同一类型的对象作为参数,但很少有类支持这一点。(小于支持可克隆的数量)

对于泛型克隆,我有一个helper方法,它创建一个类的新实例,并使用反射(实际上类似于反射,但速度更快)从原始(浅拷贝)复制字段

对于深度复制,一种简单的方法是序列化对象并将其反序列化


顺便说一句:我的建议是使用不可变对象,这样你就不需要克隆它们了

还有构建器模式。有关详细信息,请参见有效Java

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

public class C {
   public int value;
   public C() { }
   public C(C other) {
     value = other.value;
   }
}
最近也有类似的问题

公共类G{
公共价值观;
公共G(){}
公共G(G基本上,。没有任何东西可以轻易地与泛型一起工作。如果您有类似的内容(缩短以理解要点):

公共类SomeClass{
公共T复制(T对象){
return(T)object.copy();
}
}
接口可复制{
可复制副本();
}

然后,通过编译器警告,您可以完成任务。由于泛型在运行时被删除,因此执行副本的某些操作将在其中包含编译器警告生成转换。在这种情况下,这是无法避免的。在某些情况下,这是可以避免的(谢谢,kb304)但不是全部。考虑这样一种情况:您必须支持实现接口的子类或未知类(例如,您正在迭代不必生成同一类的可复制的集合)。.

您缺少的是,克隆在默认情况下和常规情况下创建浅拷贝,而让它创建深拷贝通常是不可行的

问题是,如果不能够跟踪访问过的对象,就无法真正创建循环对象图的深度副本。clone()不提供此类跟踪(因为这必须是.clone()的一个参数),因此只能创建浅层副本


即使您自己的对象为其所有成员调用.clone,它也不会是深度副本。

一种可能适用于您的模式是bean级复制。基本上,您可以使用无参数构造函数并调用各种setter来提供数据。您甚至可以使用各种bean属性库相对轻松地设置属性。这是与克隆不同,但从许多实际用途来看,这很好。

我认为Yishai的答案可以改进,这样我们就不会对以下代码发出警告:

public class SomeClass<T extends Copyable<T>> {

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

interface Copyable<T> {
    T copy();
}
公共类SomeClass{
公共T复制(T对象){
返回object.copy();
}
}
接口可复制{
T复制();
}
这样,需要实现可复制接口的类必须如下所示:

public class MyClass implements Copyable<MyClass> {

    @Override
    public MyClass copy() {
        // copy implementation
        ...
    }

}
公共类MyClass实现可复制{
@凌驾
公共MyClass副本(){
//复制实现
...
}
}
通常,clone()与受保护的复制构造函数协同工作。这是因为clone()与构造函数不同,可以是虚拟的

在从超类基派生的类体中

class Derived extends Base {
}

这样,在最简单的情况下,您将添加一个带有克隆()的虚拟复制构造函数(C++中,Joshi建议克隆为虚拟复制构造函数)。 如果您想按建议调用super.clone(),并且必须将这些成员添加到类中,则会变得更加复杂,您可以尝试以下操作

final String name;
Address address;

/// This protected copy constructor - only constructs the object from super-class and
/// sets the final in the object for the derived class.
protected Derived(Base base, String name) {
   super(base);
   this.name = name;
}

protected Object clone() throws CloneNotSupportedException {
    Derived that = new Derived(super.clone(), this.name);
    that.address = (Address) this.address.clone();
}
现在,如果执行死刑,你就有

Base base = (Base) new Derived("name");
然后你做到了

Base clone = (Base) base.clone();
这将调用派生类(上面的一个)中的clone(),这将调用super.clone()-它可能会被实现,也可能不会被实现,但建议您调用它。然后,实现将super.clone()的输出传递给一个受保护的副本构造函数,该构造函数接受一个基,您将任何最终成员传递给它

然后,该复制构造函数调用超类的复制构造函数(如果您知道它有一个),并设置最终值

返回clone()方法时,将设置所有非最终成员

精明的读者会注意到,如果您在基中有一个复制构造函数,它将被super.clone()调用-当您在受保护的构造函数中调用超级构造函数时,将再次调用,因此您可能会调用超级副本构造函数两次。如果它正在锁定资源,它可能会知道这一点。

下面是一些缺点
protected Derived() {
    super();
}

protected Object clone() throws CloneNotSupportedException {
    return new Derived();
}
final String name;
Address address;

/// This protected copy constructor - only constructs the object from super-class and
/// sets the final in the object for the derived class.
protected Derived(Base base, String name) {
   super(base);
   this.name = name;
}

protected Object clone() throws CloneNotSupportedException {
    Derived that = new Derived(super.clone(), this.name);
    that.address = (Address) this.address.clone();
}
Base base = (Base) new Derived("name");
Base clone = (Base) base.clone();