如何在Java中复制对象?

问题

考虑以下代码:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

所以,我想把dum复制到dumtwo并改变dum而不影响dumtwo。但上面的代码并没有这样做。当我在dum中改变某些东西时,同样的变化也发生在dumtwo中。

我想,当我说'dumtwo = dum时,Java只复制**引用**.那么,有没有办法创建dum的新副本并将其分配给dumtwo`?


#1 热门回答(520 赞)

创建一个复制构造函数:

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

每个对象都有一个克隆方法,可用于复制对象,但不要使用它。创建一个类并执行不正确的克隆方法太容易了。如果你打算这样做,请至少阅读Joshua Bloch在Effective Java中所说的内容。


#2 热门回答(349 赞)

**Basic:**Object以Java格式复制。

让我们假设一个对象 - 'obj1`,它包含两个对象,包含Obj1包含的Obj2

enter image description here

浅拷贝:
浅复制创建一个相同类的新实例并将所有字段复制到新实例并返回它.对象类提供了clone方法并为浅复制提供支持。

enter image description here

深拷贝:
将对象与其引用的对象一起复制时,会发生深层复制。在下面的图像显示了对它执行深度复制后的obj1。不仅复制了'obj1,而且还复制了其中包含的对象。我们可以使用Java Object Serialization`来进行深层复制。不幸的是,这种方法也存在一些问题(detailed examples)。

enter image description here

可能的问题:
 clone很难正确实现。
最好使用Defensive copying,copy constructors(作为@egaga回复)或static factory methods

  • 如果你有一个对象,你知道有一个公共clone()方法,但是你不知道编译时对象的类型,那么你就有问题了。 Java有一个名为Cloneable的接口。实际上,如果我们想要创建一个Cloneable对象,我们应该实现这个接口。 Object.clone受到保护,因此我们必须使用公共方法覆盖它以使其可访问。
  • 当我们尝试深度复制复杂对象时,会出现另一个问题。假设所有成员对象变量的clone()方法也进行深度复制,这对假设来说风险太大。你必须控制所有类中的代码。

例如,218181767将有使用序列化的深度克隆方法(Source)。如果我们需要克隆Bean,那么在org.apache.commons.beanutils(Source)中有几种实用方法。

  • cloneBean将基于可用属性getter和setter克隆bean,即使bean类本身没有实现Cloneable。
  • 对于属性名称相同的所有情况,copyProperties会将属性值从原始bean复制到目标bean。

#3 热门回答(90 赞)

请按以下步骤操作:

public class Deletable implements Cloneable{

    private String str;
    public Deletable(){
    }
    public void setStr(String str){
        this.str = str;
    }
    public void display(){
        System.out.println("The String is "+str);
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

无论你想要获得另一个对象,只需执行克隆即可。例如:

Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
                                 // object, the changes made to this object will
                                 // not be reflected to other object