Sometimes, you’ll find it convenient to make an exact copy of an object instance.  That is, produce another independent object of the same datatype, with all the attributes having the same values as the original.

This is called cloning an object.

You might think that this would be simple to do.

You’d be wrong!

The clone() method

In principle, you can clone an object by calling the object’s clone() method. 

There is a clone() method defined in the Object class, from which every other class extends.   Its signature is basically:

Object clone()

It returns a reference to the cloned Object.  It can’t return anything more specific, because it doesn’t know, a priori, what kind of object it’s dealing with.

Note: Using the clone() method is a way of creating an object without using a constructor.  You need to be aware of this, because if you place code to perform sanity checks in your class constructors, using clone will bypass those checks!

Making a Class Cloneable

Let’s imagine we have a class that we want to be able to clone itself.  Let’s call it CloneMe:

public class CloneMe
{
  // Constructor
  public CloneMe(Object object, int value)
  {
    m_object = object;
    m_value = value;
  }
  
  public void print()
  {
    System.out.println("---CloneMe object---\n" + 
                       "Object:  " + m_object + 
                       "Value:   " + m_value);
  }
  
  ///// Private data /////
  private Object m_object;
  private int m_value;
}

This compiles fine, so let’s see what happens when we try to clone it:

class MyObject
{
  public MyObject(String name)
  {
    m_name = name;
  }

  public String toString()
  {
    return "HashId: " + super.toString() + "\n" +
           "Name: " + m_name + "\n";
  }

  //// Data ////
  private String m_name;
}

public class CloneMeTest
{
  public static void main(String[] args)
  {
    MyObject mo1 = new MyObject("Monkeys");
    CloneMe cm1 = new CloneMe(mo1, 27);
    cm1.print();
    CloneMe cm2 = (CloneMe) cm1.clone();
    cm2.print();
  }
}

When we try to compile the above source file, Java refuses to compile it. It produces the following compile-time error message:

"CloneMeTest.java": clone() has protected access 
     in java.lang.Object at line 25, column 33

I’ve highlighted the offending piece of code, above.

The reason is exactly as described in the error message:  the clone method defined in class Object has protected access, which means that only subclasses of Object may call that method.

Why is it implemented this way?

Because the Object class doesn’t know anything about your class, so it doesn’t really know how to clone an object of your class.  The most it can do is do what’s known as a shallow copy of your class’s data members, which isn’t always appropriate, depending on what you class does.  The implementers wanted to be sure that programmers would understand that a shallow copy isn’t sufficient in many cases.

So what do we do?  We have to explore a bit more…

Implementing clone()

Since you can’t call the Object class’s clone() method directly, you might think that you could implement your own clone() method in your class, and then have it call the Object class’s clone() method.

So let’s try that:

public class CloneMe
{
  // Constructor
  public CloneMe(Object object, int value)
  {
    m_object = object;
    m_value = value;
  }
  
  public void print()
  {
    System.out.println("---CloneMe object---\n" + 
                       "Object:  " + m_object + 
                       "Value:   " + m_value);
  }
  
  public Object clone()
  {
    return super.clone();
  }
  
  ///// Private data /////
  private Object m_object;
  private int m_value;
}

However, when we try to compile this code, the Java compiler produces the following compile-time error:

"CloneMe.java": unreported exception java.lang.CloneNotSupportedException; 
     must be caught or declared to be thrown at line 18, column 23

It turns out that the clone method is declared as follows:

protected Object clone() throws CloneNotSupportedException

So we have to modify our clone() method to conform to the Object class’s signature:

public class CloneMe
{
  // Constructor
  public CloneMe(Object object, int value)
  {
    m_object = object;
    m_value = value;
  }
  
  public void print()
  {
    System.out.println("---CloneMe object---\n" + 
                       "Object:  " + m_object + 
                       "Value:   " + m_value);
  }
  
  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }
  
  ///// Private data /////
  private Object m_object;
  private int m_value;
}

Now it compiles!

So let’s test it:

class MyObject
{
  public MyObject(String name)
  {
    m_name = name;
  }

  public String toString()
  {
    return "HashId: " + super.toString() + "\n" +
           "Name: " + m_name + "\n";
  }

  //// Data ////
  private String m_name;
}

public class CloneMeTest
{
  public static void main(String[] args) 
                  throws CloneNotSupportedException
  {
    MyObject mo1 = new MyObject("Monkeys");
    CloneMe cm1 = new CloneMe(mo1, 27);
    cm1.print();
    CloneMe cm2 = (CloneMe) cm1.clone();
    cm2.print();
  }
}

Note that I had to add the throws CloneNotSupportedException to get the above to compile.  (This relates to the rules governing how exceptions are handled, which we haven’t talked about yet.  Just take this change on faith, at least for the moment.)

OK, the above compiles.  What happens when we run it?  We get the following:

Exception in thread "main" java.lang.CloneNotSupportedException: CloneMe
	at java.lang.Object.clone(Native Method)
	at CloneMe.clone(CloneMe.java:18)
	at CloneMeTest.main(CloneMeTest.java:25)

What’s wrong, now?

The Cloneable Interface

It turns out that the Object class’s clone() method refuses to work if your class doesn’t implement the Cloneable interface. 

What’s the Cloneable interface?

Java provides an interface Cloneable, in the package java.lang.  Here is the code that defines it (with comments removed):

package java.lang;

public interface Cloneable
{
}

That is everything you need to know about interface Cloneable!

Notice that it is a marker interface, because it contains absolutely no methods, nor anything else.

The idea is that you can only call the Object class’s clone() method if your class implements this interface.  So let’s do that:

public class CloneMe implements Cloneable
{
  // Constructor
  public CloneMe(Object object, int value)
  {
    m_object = object;
    m_value = value;
  }
  
  public void print()
  {
    System.out.println("---CloneMe object---\n" + 
                       "Object:  " + m_object + 
                       "Value:   " + m_value);
  }
  
  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }
  
  ///// Private data /////
  private Object m_object;
  private int m_value;
}

Now, this compiles, and when you test it:

class MyObject
{
  public MyObject(String name)
  {
    m_name = name;
  }

  public String toString()
  {
    return "HashId: " + super.toString() + "\n" +
           "Name: " + m_name + "\n";
  }

  //// Data ////
  private String m_name;
}

public class CloneMeTest
{
  public static void main(String[] args) 
                  throws CloneNotSupportedException
  {
    MyObject mo1 = new MyObject("Monkeys");
    CloneMe cm1 = new CloneMe(mo1, 27);
    cm1.print();
    CloneMe cm2 = (CloneMe) cm1.clone();
    cm2.print();
  }
}

it produces the following output:

---CloneMe object---
Object: HashId: MyObject@923e30
Name: Monkeys
Value: 27
---CloneMe object---
Object: HashId: MyObject@923e30
Name: Monkeys
Value: 27

We’ve finally succeeded in cloning the object!

So we’re done, right?

Nope!  Take a look at the output more carefully.  While we actually have two distinct object instances of type CloneMe, each of those instances contain an Object reference which points to a single instance of MyObject.  That’s what I meant by the Object class’s clone() method doing a shallow copy.  It copied the reference, not what the reference referred to.

Depending on what our class is designed to do, this may be appropriate, or it may be completely wrong.

Under what circumstances can you think of where it might be incorrect?

Fixing Shallow Copies

So what if your class requires something more sophisticated than a simple shallow copy?

You need to put more into your class’s clone method:

public class CloneMe implements Cloneable
{
  // Constructor
  public CloneMe(MyObject object, int value)
  {
    m_object = object;
    m_value = value;
  }
  
  public void print()
  {
    System.out.println("---CloneMe object---\n" + 
                       "Object:  " + m_object + 
                       "Value:   " + m_value);
  }
  
  public Object clone() throws CloneNotSupportedException
  {
    CloneMe cloned = (CloneMe) super.clone();
    cloned.m_object = (MyObject) m_object.clone();
    return cloned;
  }
  
  ///// Private data /////
  private MyObject m_object;
  private int m_value;
}

We use the Object class’s clone() method to create our new object, and then add code that fixes up the shallow copy problems.  In this case, I’ve changed the m_object instance variable to refer to a MyObject, which I clone to create a fresh instance of that object.

This means that I had to change the implementation of MyObject to support cloning:

class MyObject implements Cloneable
{
  public MyObject(String name)
  {
    m_name = name;
  }
  
  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }

  public String toString()
  {
    return "HashId: " + super.toString() + "\n" +
           "Name: " + m_name + "\n";
  }

  //// Data ////
  private String m_name;
}

public class CloneMeTest
{
  public static void main(String[] args) 
                       throws CloneNotSupportedException
  {
    MyObject mo1 = new MyObject("Monkeys");
    CloneMe cm1 = new CloneMe(mo1, 27);
    cm1.print();
    CloneMe cm2 = (CloneMe) cm1.clone();
    cm2.print();
  }
}

This now produces the following output:

---CloneMe object---
Object:  HashId: MyObject@923e30
Name: Monkeys
Value:   27
---CloneMe object---
Object:  HashId: MyObject@130c19b
Name: Monkeys
Value:   27

Which, as you can see, now has references to two different MyObject instances, one for each cloned CloneMe instance.

WHEW!