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?
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()); } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With