Apps

Pick up tips about cloning Java objects


Objects in Java are referred using reference types, and there is no direct way to copy the contents of an object into a new object. The assignment of one reference to another merely creates another reference to the same object. Therefore, a special clone() method exists for all reference types in order to provide a standard mechanism for an object to make a copy of itself. Here are the details you need to know about cloning Java objects.

Why create a local copy?

The most probable reason for creating a local copy of an object is because you plan to modify the object, and you don't want to modify the method caller's object. If you decide that you need a local copy, you can perform the operation by using the clone() method of the Object class. The clone() method is defined as protected, but you must redefine it as public in all subclasses that you might want to clone.

For example, the standard library class ArrayList overrides clone(), so you can call clone() for ArrayList, like this:

import java.util.*;class MyInt {

private int i;

public MyInt(int ii) { i = ii; }

public void increment() { i++; }

public String toString() {

return Integer.toString(i);

}

}public class Test {

public static void main(String[] args) {

ArrayList al = new ArrayList();

for(int i = 0; i < 10; i++ )

al.add(new MyInt(i));

ArrayList al1 = (ArrayList)al.clone();

// Increment all al1's elements:

for(Iterator e = al1.iterator(); e.hasNext(); )

((MyInt)e.next()).increment(); }

}

The clone() method produces an Object, which must be recast to the proper type. This example shows how ArrayList's clone() method does not automatically try to clone each of the objects that the ArrayList contains -- the old ArrayList and the cloned ArrayList are aliased to the same objects. This is often called a shallow copy, since it's only copying the "surface" portion of an object. The actual object consists of this "surface," plus all the objects that the references are pointing to and all the objects those objects are pointing to, etc. This is often referred to as the "Web of objects." When you copy the entire mess, it is called a deep copy.

The Cloneable interface and deep copies

By default, classes in Java do not support cloning; the default implementation of the clone() method throws a CloneNotSupportedException. You should override implementation of the clone() method. Remember that you must make it public and, inside the method, your first action must be super.clone(). Classes that want to allow cloning must implement the marker interface Cloneable. Since the default implementation of Object.clone only performs a shallow copy, classes must also override clone to provide a custom implementation when a deep copy is desired. Basically, if you want to make objects of your class publicly cloneable, you need code like this:

class Test implements Cloneable

{

...

public Object clone()

{

try

{

return super.clone();

}

catch ( CloneNotSupportedException e )

{

return null;

}

}

...

}

If you are happy with a protected clone, which just blindly copied the raw bits of the object, you don't need to redefine your own version. However, you will usually want a public one. (Note: You can't create a private or default scope clone; you can only increase the visibility when you override.)

Possible problems and a solution

Since the clone() method is protected, subclasses have to explicitly agree to be cloneable by overriding this protected method with a public method. All of the Collections classes do this. The subclass also has to implement Cloneable for the default cloning mechanism in Object.clone() to work.

If you have an object that you know has a public clone() method, but you don't know the type of the object at compile time, you have problems. For instance, say x is declared as an Object. You can't just call x.clone() because Object.clone() is protected. If Cloneable defined a public clone() method, you could use ((Cloneable) x).clone(), but it doesn't. You either have to enumerate all the classes that you think x could be, or you have to resort to reflection.

Another problem arises when you try deep copying of a complex object. You're assuming that the clone() method of all member object variables also does deep copy; this is too risky of an assumption. You must control the code in all classes, or you must know that all classes involved in deep copy operation do such a copy in the right way.

One solution to these problems is to clone using serialization. Serialization is usually used to send objects off somewhere (such as into a file or over the network) so that somebody else can reconstruct them later. You can abuse serialization to immediately reconstruct the object yourself. If the object is serializable at all, the reconstruction should be a faithful copy. In normal uses of serialization, the original object is nowhere near a faithful copy; it could be on the other side of the world at the far end of a network connection. You can be sure that changing the copy will have no effect on the original.

Peter V. Mikhalenko is a Sun certified professional who works for Deutsche Bank as a business consultant.

---------------------------------------------------------------------------------------

Get Java tips in your inbox Delivered each Thursday, our free Java newsletter provides insight and hands-on tips you need to unlock the full potential of this programming language. Automatically subscribe today!
10 comments
kaur manjit
kaur manjit

object clone is protected ,so must overide it with a public method in order make it acessable,reflectively,but it will be complicated then

sangraal
sangraal

I just implement a clone() method that deep copies everything to avoid any questionable methodology.

obifromsouthlondon
obifromsouthlondon

I'd gone through the pain of making class in my inheritance hierarchy clonable. could have just made them serializable and make copies that way. now time to refactor ...

Justin James
Justin James

I think the whole issue really exposes a fundamental issue with the OO paradigm. Everything is so black boxed, who knows what really happens? For example, let's say I try doing something like (please forgive the pseudo Java/C# mush): public class myClass{ private int _counter; private string _property1; public property string property1 { get { _counter++; return _property1; } set (string value) { _property1 = value; } public void new() { _counter = 0; _property1 = String.Empty; } public myClass Clone() { myClass selfClone = new myClass(); selfClone.property1 = this.property1; return selfClone; } } Now, someone using this class as a property in their class then does something like: public class foo { private myClass _bar; public property myClass bar { get { return _bar; } set (myClass value) { _bar = value; } } public void new() { _bar = new myClass(); } public foo Clone() { foo selfClone = new foo(); selfClone.bar = _bar.Clone(); //WARNING! return selfClone; } } As you can see, the author of the foo class has no idea what happens internally in the myClass class. As a result, foo's "deep copy" actually is not so deep. Indeed, it is *impossible* for foo's author to implement anything that accurately represents the contents of myClass. Any efforts to clone or copy myClass.property1 are going to alter the value of _counter, unless you are within myClass and can directly access _property1. Why? Well, maybe myClass's author insists that a true copy if that class should be impossible; perhaps the business rule is that _counter needs to be incremented any time access from outside of myClass occurs, regardless of the purpose. Because myClass and foo disagree on the concept of "cloning", consumers of foo may be quite surprised when foo.bar.Serialize() != foo.bar.Clone() when compared on a byte-for-byte basis! :( J.Ja

jean-simon.s.larochelle
jean-simon.s.larochelle

Joshua Bloch in "Effective Java Programming" says (item 54): "Implement Serializable judiciosly" Implementing Serializable "places a significant burden on anyone who extends the class or implements the interface". I have experienced this first hand and believe me you don't want to do this unless you have very good reasons to do so. It should certainly not be used as a "standard" method to implement Cloneable. Check out "Effective Java Programming" (item 10): "Override clone judiciously" for more details and alternate methods of cloning. For one thing serializing will often be slower than a proper cloning method because everything gets serialized (transient is useless in this context) and immutable members like String do not need to be deep copied (copying the reference using the super.clone() method is sufficient). JS

Justin James
Justin James

Yes, a very good article! I especially like that same piece at the end. I deliberately avoid any kind of clone because it's like "thread safe", who knows how the cloning was implemented? But doing a serialization copy, that makes sense. Assuming, of course, that all of the objects in the tree support that. :) This is one of those things where I think it would have been better for the language to define these things and how they need to happen, instead of hoping that the person implementing it documents it well enough to make sense. J.Ja

jean-simon.s.larochelle
jean-simon.s.larochelle

..and if it is not and you plan to use it you should test it. Special implementations should be documented carefully. For example if a clone() method does not obey the rule: object.clone().equals(object) If you don't have the documentation for a class or access to the source code you should write a unit test to check your expectations. JS

Justin James
Justin James

Personally, due to the huge problems with the concept of "cloning" in OO (my opinion, purely), I do not implement Clone() methods nor do I consume them, but that is good informtion and good points. J.Ja

Justin James
Justin James

I think clone() and thread safety are very comparable... they are implementation of some fairly low-level stuff and it is critical that a) what has been done be documented, and b) the documentation is explicit (not in an "adult content" way). "Thread safe" means different things to different people, and so do "deep copy" and "shallow copy". I agree that doumentation (and reading it) is critical here! J.Ja