Reputation: 3205
I have an object that I need to copy in Java. I need to create a copy and run some tests on it without changing the original object itself.
I assumed that I needed to use the clone() method, but this is protected. Having done some research on the net, I can see that this can be overriden with a public method in my class. But I cannot find an explanation on how to do this. How could this be done?
Also, is this the best way of achieving what I need?
Upvotes: 21
Views: 77325
Reputation: 28069
For test code Serialization is maybe the safest answer, especially if the object is already Serializable try Apache Commons SerializationUtils for an implementation.
Upvotes: 9
Reputation: 27
You can use org.apache.commons.lang3.SerializationUtils class for object cloning, - Class should implement Serializable interface.
SerializationUtils.clone is also supported on Google App Engine instance
Upvotes: 3
Reputation: 11858
Another option by using Copy Constructor (from 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());
}
}
Upvotes: 30
Reputation: 28696
Some options:
Cloneable
for your object and put clone()
method as public. See full explanation here: http://www.cafeaulait.org/course/week4/46.htmlSerializable
interface for the object and all its fields.XStream
to perform serialization via XML - you won't have to implement anything here.Upvotes: 14
Reputation: 16516
There are multiple ways to copy object in java(shallow or deep).
This Answer will help you.
Upvotes: 2
Reputation: 4184
There are two popular approaches. One is to provide a clone
method as you mentioned, like so.
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();
}
}
Pay attention to the "copy fields ... here!" part. The initial result
is only a shallow copy, meaning that if there's a reference to an object, both the original and result
will share the same object. For example, if C
contains private int[] data
you'd probably want to copy that.
...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...
Note that you don't need to copy primitive fields, as their content is already copied, or immutable objects, as they can't change anyways.
The second approach is to provide a copy constructor.
public class C {
public C(final C c) {
// initialize this with c
}
}
Or a copy factory.
public class C {
public static C newInstance(final C c) {
return new C(c);
}
private C(final C c) {
// initialize this with c
}
}
Both approaches have their respective properties. clone
is nice because its a method, so you don't have to know the exact type. In the end, you should always end up with a "perfect" copy. The copy constructor is nice because the caller has a chance to decide, as can be seen by the 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
I recommend choosing either approach, whichever suits you better.
I'd use the other approaches, like reflective copying or immediate serializing/deserializing, in unit tests only. To me, they feel less appropriate for production code, mainly because of performance concerns.
Upvotes: 21
Reputation: 272397
Joshua Bloch has some interesting things to say about cloneable. Depending on the size/construction of the object, I'd add a copy constructor to the object, or serialise/deserialise using one of the solutions mentioned above.
Upvotes: 2