Tray
Tray

Reputation: 3205

Copy an object in Java

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

Answers (7)

Gareth Davis
Gareth Davis

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

A.G
A.G

Reputation: 27

You can use org.apache.commons.lang3.SerializationUtils class for object cloning, - Class should implement Serializable interface.

  • ClassName copyobject = SerializationUtils.clone(classobjectTocopy)

SerializationUtils.clone is also supported on Google App Engine instance

Upvotes: 3

ecleel
ecleel

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

Yoni Roit
Yoni Roit

Reputation: 28696

Some options:

  • You can implement Cloneable for your object and put clone() method as public. See full explanation here: http://www.cafeaulait.org/course/week4/46.html
    However, this produces a shallow copy and might be not something you want.
  • You can serialize and deserialize your object. You will need to implement Serializable interface for the object and all its fields.
  • You can use XStream to perform serialization via XML - you won't have to implement anything here.

Upvotes: 14

Chandra Sekhar
Chandra Sekhar

Reputation: 16516

There are multiple ways to copy object in java(shallow or deep).
This Answer will help you.

Upvotes: 2

Ronald Blaschke
Ronald Blaschke

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

Brian Agnew
Brian Agnew

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

Related Questions