我有一个对象需要用Java复制。我需要创建一个副本并在其上运行一些测试,而无需更改原始对象本身。用Java复制对象
我认为我需要使用clone()方法,但这是受保护的。在网上做了一些研究后,我可以看到,这可以在我的班级中用公开的方法重写。但我找不到解释如何做到这一点。这怎么能做到?
此外,这是实现我所需要的最佳方式吗?
我有一个对象需要用Java复制。我需要创建一个副本并在其上运行一些测试,而无需更改原始对象本身。用Java复制对象
我认为我需要使用clone()方法,但这是受保护的。在网上做了一些研究后,我可以看到,这可以在我的班级中用公开的方法重写。但我找不到解释如何做到这一点。这怎么能做到?
此外,这是实现我所需要的最佳方式吗?
一些选项:
Cloneable
为对象,并把clone()
方法公开。请参阅此处的完整说明:http://www.cafeaulait.org/course/week4/46.htmlSerializable
界面。XStream
通过XML执行序列化 - 您不必在此处执行任何操作。对于测试代码序列化可能是最安全的答案,特别是如果对象已经Serializable,请尝试Apache Commons SerializationUtils来实现。
使用拷贝构造函数(从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());
}
}
我不会在复制构造函数中使用getter。首先你不需要它们,因为你总是可以访问实例变量。其次,如果你自己做这个练习,你可能会通过创建太多的getter来降低封装。最后它可能容易出错。想象一下,你调整getMass()中的值比将调整后的值复制到新对象的实例变量中,如果你在新对象上调用getMass,则会再次调整该值。 – 2010-07-28 08:21:58
约书亚布洛赫有some interesting things to say about cloneable。根据对象的大小/构造,我会为该对象添加一个复制构造函数,或者使用上述解决方案之一来添加序列化/反序列化。
有两种流行的方法。其中之一就是像上面提到的那样提供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
我建议选择任何一种方法,以适合您为准。
我只会在单元测试中使用其他方法,如反射复制或立即序列化/反序列化。对我来说,他们觉得不适合生产代码,主要是因为性能问题。
有多种方法可以在java中复制对象(浅或深)。
这Answer将帮助你。
您可以使用org.apache.commons.lang3.SerializationUtils类进行对象克隆, - 类应该实现Serializable接口。
SerializationUtils.clone也支持谷歌应用程序引擎实例
这是仅用于测试目的(单元测试),或您是否需要实际生产代码中的此功能? – crunchdog 2010-11-01 22:56:42