协慌网

登录 贡献 社区

如何在 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

答案

创建一个复制构造函数:

class DummyBean {
  private String dummy;

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

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

基本: Java 中的对象复制。

让我们假设一个对象 - obj1 ,包含两个对象,containedObj1containedObj2。
在此输入图像描述

浅拷贝:
浅复制创建一个新的instance同一类,并将所有字段添加到新的实例,并返回它。 Object 类提供clone方法,并为浅复制提供支持。
在此输入图像描述

深拷贝:
将对象与其引用的对象一起复制时,会发生深层复制。下图显示了对其执行深度复制后的obj1不仅复制了obj1 ,而且还复制了其中包含的对象。我们可以使用Java Object Serialization来进行深层复制。不幸的是,这种方法也有一些问题( 详细的例子 )。
在此输入图像描述

可能的问题:
clone很难正确实现。
最好使用防御性复制复制构造函数 (如 @egaga 回复)或静态工厂方法

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

例如, org.apache.commons.lang.SerializationUtils将使用序列化( )进行深度克隆的方法。如果我们需要克隆 Bean,那么org.apache.commons.beanutilsSource )中有几个实用程序方法。

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

在包中import org.apache.commons.lang.SerializationUtils;有一种方法:

SerializationUtils.clone(Object);

例:

this.myObjectCloned = SerializationUtils.clone(this.object);