复制Java中的对象

复制Java中的对象,java,object,copy,clone,Java,Object,Copy,Clone,我有一个需要用Java复制的对象。我需要创建一个副本并在其上运行一些测试,而不更改原始对象本身 我假设我需要使用clone()方法,但这是受保护的。在网上做了一些研究之后,我发现这可以在我的类中用一个公共方法重写。但我找不到一个解释来解释如何做到这一点。这怎么可能呢 此外,这是实现我所需的最佳方式吗?一些选项: 您可以为对象实现Cloneable,并将clone()方法作为公共方法。请参见此处的完整说明: 但是,这会产生一个浅拷贝,可能不是您想要的 您可以序列化和反序列化对象。您需要为对象及其

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

我假设我需要使用clone()方法,但这是受保护的。在网上做了一些研究之后,我发现这可以在我的类中用一个公共方法重写。但我找不到一个解释来解释如何做到这一点。这怎么可能呢

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

一些选项:

  • 您可以为对象实现
    Cloneable
    ,并将
    clone()
    方法作为公共方法。请参见此处的完整说明:
    但是,这会产生一个浅拷贝,可能不是您想要的
  • 您可以序列化和反序列化对象。您需要为对象及其所有字段实现
    Serializable
    接口
  • 您可以使用来通过XML执行序列化—您不必在这里实现任何东西

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

使用复制构造函数的另一个选项(从):


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

有两种流行的方法。一个是提供一个
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();
        }
}
请注意“复制字段…此处!”部分。最初的
结果
只是一个浅拷贝,这意味着如果存在对某个对象的引用,则原始结果和
结果
将共享同一个对象。例如,如果
C
包含
private int[]数据
,您可能需要复制该数据

...
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集合所示

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
我建议你选择其中一种方法,哪一种更适合你


我只在单元测试中使用其他方法,如反射复制或即时序列化/反序列化。对我来说,它们不太适合生产代码,主要是因为性能问题。

在java中复制对象有多种方法(浅拷贝或深拷贝)。

这将对您有所帮助。

您可以使用org.apache.commons.lang3.SerializationUtils类进行对象克隆, -类应实现可序列化接口

  • ClassName copyobject=SerializationUtils.clone(classobjectTocopy)

Google App Engine实例也支持SerializationUtils.clone,我不会在复制构造函数中使用getter。首先,您不需要它们,因为您始终可以访问实例变量。第二,如果您自己进行实践,您可能会通过创建太多的getter来降低封装。最后,它可能容易出错。假设您在getMass()中调整了值,然后将调整后的值复制到新对象的实例变量中,如果您在新对象上调用getMass,该实例变量将再次调整该值。@Mr_和Mrs_,您是对的-我在第一次读取时没有发现这一点。Norbert的观点仍然站得住脚。这只是为了测试目的(单元测试),还是在实际的生产代码中需要这个功能?
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