To clone something is to make a duplicate of
it. The clone( )
method in Java makes an exact
duplicate of an object. Why do we need cloning? Java’s method
calling semantics are call-by-reference, which allows the
called method to modify the state of an object that is passed into
it. Cloning the input object before calling the method would pass a
copy of the object, keeping your original safe.
How can you clone? Cloning is not “enabled” by default in classes that you write.
Object o = new Object( ); Object o2 = o.clone( );
If you try calling clone( )
without any special
preparation, as in this excerpt from
Clone0.java
, you will see a message like this
(from the Jikes compiler; the javac message may
not be as informative):
Clone0.java:4:29:4:37: Error: Method "java.lang.Object clone( );" in class "java/ lang/Object" has protected or default access. Therefore, it is not accessible in class "Clone0" which is in a different package.
You must take two steps to make your class cloneable:
The class java.lang.Object
declares its clone
protected and
native
.
Protected
classes can be called by a subclass or those in the same package
(i.e., java.lang
), but not by unrelated classes.
That is, you can call Object.clone( )
-- the
native method that does the magic of duplicating the
object -- only from within the object being cloned. Here is a
simple example of a class with a clone method, and a tiny program
that uses it:
public class Clone1 implements Cloneable { /** Clone this object. Just call super.clone( ) to do the work */ public Object clone( ) throws CloneNotSupportedException { return super.clone( ); } int x; transient int y; // will be cloned, but not serialized public static void main(String[] args) { Clone1 c = new Clone1( ); c.x = 100; c.y = 200; try { Object d = c.clone( ); System.out.println("c=" + c); System.out.println("d=" + d); } catch (CloneNotSupportedException ex) { System.out.println("Now that's a surprise!!"); System.out.println(ex); } } /** Display the current object as a string */ public String toString( ) { return "Clone1[" + x + "," + y + "]"; } }
The clone( )
method in Object
throws
CloneNotSupportedException
.
This is to handle the case of inadvertently calling clone( )
on a class that isn’t supposed to be cloned. Since
most of the time you don’t need to do anything with this
exception, a clone method can simply declare this exception in its
throws
clause, and let the calling code deal with
it.
Calling Object
’s clone( )
does a stateful, shallow copy down inside the
JVM. That is, it creates a new object, and copies all the fields from
the old object into the new. It then returns the new reference as an
Object
; you need to cast it to the appropriate
object type. So if that’s all there is, why do you even have to
write this method? The reason is to give you a chance to do any
preservation of state that is required in cloning your objects. For
example, if your class has any
references
to other objects (and most real-world classes do), you may well want
to clone them as well! The default clone method simply copies all the
object’s state, so that you now have two references to each
object. Or you might have to close and reopen files, to avoid having
two threads (see Chapter 24) reading from or
writing into the same file. In effect, what you have to do here
depends on what the rest of your class does.
Now suppose that you clone a class containing an
array of objects.
You now have two references to objects in the array, but further
additions to the array will only be made in one array or the other.
Imagine a Vector
, Stack
, or
other collection class being used in your class,
and your object gets cloned!
The bottom line is that most object references need to be cloned.
Even if you don’t need clone()
, your
subclasses may! If you
didn’t provide clone( )
in a class
subclassed from Object
, your subclasses will
probably get the Object
version, which will cause
problems if there are collections or other mutable objects referred
to. As a general rule, you should provide clone( )
even if only your own subclasses would need it.
3.137.183.210