- clone (Java method)
-
clone()
is a method in the Java programming language for object duplication. In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone() method provides this missing functionality.Contents
Overview
Classes that want copying functionality must implement some method to do so. To a certain extent that function is provided by "
Object.clone()
".clone()
acts like a copy constructor. Typically it calls theclone()
method of its superclass to obtain the copy, etc. until it eventually reachesObject
'sclone()
method. The specialclone()
method in the base classObject
provides a standard mechanism for duplicating objects.The class
Object
'sclone()
method creates and returns a copy of the object, with the same class and with all the fields having the same values. However,Object.clone()
throws aCloneNotSupportedException
unless the class you are trying to use it on implements the marker interfaceCloneable
.The default implementation of
Object.clone()
performs a shallow copy. When a class desires a deep copy or some other custom behavior, they must perform that in their ownclone()
method after they obtain the copy from the superclass.The syntax for calling
clone
in Java is (assumingobj
is a variable of a class type that has a publicclone()
method):Object copy = obj.clone();
or commonly
MyClass copy = (MyClass) obj.clone();
which provides the typecasting needed to assign the generic
Object
reference returned fromclone
to a reference to aMyClass
object.One disadvantage with the design of the
clone()
method is that the return type ofclone()
isObject
, and needs to be explicitly cast back into the appropriate type. However, overridingclone()
to return the appropriate type is preferable and eliminates the need for casting in the client (using covariant return types, since J2SE 5.0).Another disadvantage is that one often cannot access the
clone()
method on an abstract type. Most interfaces and abstract classes in Java do not specify a publicclone()
method. As a result, often the only way to use theclone()
method is if you know the actual class of an object; which is contrary to the abstraction principle of using the most generic type possible. For example, if one has aList
reference in Java, one cannot invokeclone()
on that reference becauseList
specifies no publicclone()
method. Actual implementations ofList
likeArrayList
andLinkedList
all generally haveclone()
methods themselves, but it is inconvenient and bad abstraction to carry around the actual class type of an object.Alternatives
There are alternatives to
clone()
, notably the use of a copy constructor - a constructor that accepts as a parameter another instance of the same class - or a factory method. These methods are not always adequate when the concrete type of the cloned object is not known in advance. (However,clone()
is often not adequate either for the same reason, as most abstract classes do not implement a publicclone()
method.)Also the use of serialization and deserialization is another alternative to using clone.
clone()
and the Singleton patternWhen writing a class using the Singleton pattern, only one instance of that class can exist at a time. As a result, the class must not be allowed to make a clone. To prevent this, override the
clone()
method using the following code:public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }
(Note: This is only necessary if a superclass implements a public
clone()
method, or to prevent a subclass from using this class'sclone()
method to obtain a copy. Since classes don't usually inherit a publicclone()
method (Object
doesn't have a publicclone()
method), it is usually unnecessary to explicitly implement a non-functionalclone()
method.clone()
and class hierarchyWhen working with the clone() in a hierarchy of classes, there are several things that must be handled properly.
1) Every type reference that needs to be cloned must have a clone() method in its own class or a publicly accessible clone() method in its parent classes. That means that if you want to clone a reference to an abstract base class, either the base class must have a clone() method, or one of its parents must have a publicly accessible clone() method.
Example:
since varY1 is of type Y, then Y must have clone(), or a parent of Y must have clone()
abstract public class X implements Cloneable { public X clone() throws CloneNotSupportedException { return (X) super.clone(); } } abstract public class Y extends X { } public class Z extends Y { } public class test1 { public void function() throws CloneNotSupportedException { Y varY1 = new Z(); Y varY2 = (Y) varY1.clone(); } }
2) Every class that has any data other than primitives that has to be cloned must contain a clone() function that handles it. This includes all objects and all primitives that are allocated with the 'new' command such as variable length arrays. (This assumes that the programmer wants the objects to be cloned (deep copy) and not just have their reference copied (shallow copy).)
Example:
since class Z has a reference to an object of another class, there needs to be specific code to clone that object.
abstract public class X implements Cloneable { public X clone() throws CloneNotSupportedException { return (X) super.clone(); } } abstract public class Y extends X { } public class ObjectABC implements Cloneable { public ObjectABC clone() throws CloneNotSupportedException { return (ObjectABC) super.clone(); } } public class Z extends Y { private ObjectABC someABC; public Z clone() throws CloneNotSupportedException { Z newZ = (Z) super.clone(); newZ.someABC = someABC.clone(); return newZ; } } public class test1 { public void function() throws CloneNotSupportedException { Y varY1 = new Z(); Y varY2 = (Y) varY1.clone(); } }
Easy Solution:
The easiest solution to this is to make the base class "implements Cloneable" and have the base class and all sub-classes contain the clone() method. When a class has data in it that must be cloned, adding a line or two to the clone() method is straight forward.
Example:
abstract public class X implements Cloneable { public X clone() throws CloneNotSupportedException { return (X) super.clone(); } } abstract public class Y extends X { public Y clone() throws CloneNotSupportedException { return (Y) super.clone(); } } public class Z extends Y { public Z clone() throws CloneNotSupportedException { return (Z) super.clone(); } } public class test1 { public void function() throws CloneNotSupportedException { Y varY1 = new Z(); Y varY2 = varY1.clone(); } }
Downsides:
If every class in your hierarchy has a clone() method, then when the actual class is cloned all of these functions will be called, adding some overhead. Over many calls this could be significant.
With complex object graphs deep copying can become problematic, with recursive references. Once one object is cloneable, others tend to follow until the entire graph attempts to implement Cloneable. Sooner or later you run into a class that you can't make Cloneable.
It is not always appropriate to have multiple copies of the same object floating around. Besides, using clone() tends to defeat the "single object, multiple references" paradigm.
clone()
andfinal
fieldsGenerally,
clone()
is incompatible withfinal
fields. Becauseclone()
is essentially a default constructor (one that has no arguments) it is impossible to assign afinal
field within aclone()
method; a compiler error is the result. Where the value of the field is an immutable object this is okay; just let the 'constructor' copy the reference and both the original and its clone will share the same object.But where the value is a mutable object it must be deep copied. The only solution is to remove the
final
modifier from the field, giving up the benefits the modifier conferred.For this reason, some programmers suggest to make the objects in the hierarchy Serializable, and create copies by serializing the old object and then creating a new object from the resulting bitstream, which handles final data members correctly, but is significantly slower.[1]
External links
- McManus, Eamonn (April 4, 2007). "Cloning Java objects using serialization". Eamonn McManus's Blog. java.net. http://weblogs.java.net/blog/2007/04/04/cloning-java-objects-using-serialization. Retrieved 2010-11-16.
- Bloch, Joshua (2008). Effective Java: A Programming Language Guide. The Java Series (2nd ed.). Addison-Wesley. ISBN 0321356683.
- "Avoid clone". Collected Java Practices. Hirondelle Systems. 2009. http://www.javapractices.com/topic/TopicAction.do?Id=71. Retrieved 2009-07-31.
- "Object (Java Platform SE 6)". Java Platform Standard Ed. 6. Sun Microsystems, Inc.. 2008. http://java.sun.com/javase/6/docs/api/java/lang/Object.html#clone(). Retrieved 2009-07-31.
- Roulo, Mark. (01/01/99) How to avoid traps and correctly override methods from java.lang.Object JavaWorld.com - Covers the basics of implementing the clone method.
References
Categories:- Java programming language
Wikimedia Foundation. 2010.