用Java复制对象

我有一个需要用Java复制的对象。 我需要创建一个副本并在其上运行一些测试而不更改原始对象本身。

我假设我需要使用clone()方法,但这是受保护的。 在网上做了一些研究之后,我可以看到这可以用我class上的公共方法覆盖。 但我找不到如何做到这一点的解释。 怎么可以这样做?

此外,这是实现我需要的最佳方式吗?

使用Copy Constructor的另一个选项(来自Java Practices ):

public final class Galaxy { public Galaxy (double aMass, String aName) { fMass = aMass; fName = aName; } /** * Copy constructor. */ public Galaxy(Galaxy aGalaxy) { this(aGalaxy.getMass(), aGalaxy.getName()); //no defensive copies are created here, since //there are no mutable object fields (String is immutable) } /** * Alternative style for a copy constructor, using a static newInstance * method. */ public static Galaxy newInstance(Galaxy aGalaxy) { return new Galaxy(aGalaxy.getMass(), aGalaxy.getName()); } public double getMass() { return fMass; } /** * This is the only method which changes the state of a Galaxy * object. If this method were removed, then a copy constructor * would not be provided either, since immutable objects do not * need a copy constructor. */ public void setMass( double aMass ){ fMass = aMass; } public String getName() { return fName; } // PRIVATE ///// private double fMass; private final String fName; /** * Test harness. */ public static void main (String... aArguments){ Galaxy m101 = new Galaxy(15.0, "M101"); Galaxy m101CopyOne = new Galaxy(m101); m101CopyOne.setMass(25.0); System.out.println("M101 mass: " + m101.getMass()); System.out.println("M101Copy mass: " + m101CopyOne.getMass()); Galaxy m101CopyTwo = Galaxy.newInstance(m101); m101CopyTwo.setMass(35.0); System.out.println("M101 mass: " + m101.getMass()); System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass()); } } 

有两种流行的方法。 一种是提供你提到的clone方法,就像这样。

 public class C implements Cloneable { @Override public C clone() { try { final C result = (C) super.clone(); // copy fields that need to be copied here! return result; } catch (final CloneNotSupportedException ex) { throw new AssertionError(); } } 

注意“复制字段……在这里!” 部分。 初始result只是一个浅拷贝,这意味着如果有一个对象的引用,原始和result将共享同一个对象。 例如,如果C包含private int[] data您可能想要复制它。

 ... final C result = (C) super.clone(); result.data = data.clone(); return result; ... 

请注意,您不需要复制原始字段,因为它们的内容已被复制,或者不可变对象,因为它们无论如何都无法更改。

第二种方法是提供复制构造函数。

 public class C { public C(final C c) { // initialize this with c } } 

或者是复印厂。

 public class C { public static C newInstance(final C c) { return new C(c); } private C(final C c) { // initialize this with c } } 

两种方法都有各自的属性。 clone很好,因为它是一个方法,所以你不必知道确切的类型。 最后,你应该总是得到一个“完美”的副本。 复制构造函数很好,因为调用者有机会决定,Java Collections可以看到。

 final List c = ... // Got c from somewhere else, could be anything. // Maybe too slow for what we're trying to do? final List myC = new ArrayList(c); // myC is an ArrayList, with known properties 

我建议选择哪种方法,哪个更适合你。

我只在unit testing中使用其他方法,如reflection复制或立即序列化/反序列化。 对我来说,他们觉得不太适合生产代码,主要是因为性能问题。

一些选择:

  • 您可以为对象实现Cloneable并将clone()方法设置为public。 请参阅此处的完整说明: http : //www.cafeaulait.org/course/week4/46.html
    但是,这会产生浅拷贝,可能不是您想要的。
  • 您可以序列化和反序列化您的对象。 您需要为对象及其所有字段实现Serializable接口。
  • 您可以使用XStream通过XML执行序列化 – 您不必在此处实现任何内容。

对于测试代码,序列化可能是最安全的答案,特别是如果对象已经是Serializable,请尝试使用Apache Commons SerializationUtils进行实现。

您可以使用org.apache.commons.lang3.SerializationUtils类进行对象克隆, – Class应该实现Serializable接口。

  • ClassName copyobject = SerializationUtils.clone(classobjectTocopy)

Google App Engine实例也支持SerializationUtils.clone

有多种方法可以在java(浅或深)中复制对象。
本答案将帮助您。

约书亚布洛赫有一些关于克隆的有趣的事情 。 根据对象的大小/结构,我将向对象添加一个复制构造函数,或者使用上面提到的解决方案之一进行序列化/反序列化。