Cloning in Java

In Java, when you assign an object to another variable, only the memory address of the object is copied and hence any changes in the original object will be reflected in the new variable.

MainObject obj1 = new MainObject();
obj2 = obj2;

Here, in this case any changes you make to obj1 will reflect in obj2 and vice versa. Well, if this is what you want, then no issues but if you dont want the change made in obj2 to be seen in obj1 or any change made in obj1 to be seen in obj2, then cloning comes into picture.

So what is cloning?

Well, cloning means creating a copy of the object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:

x.clone() != x

will be true, and that the expression:

x.clone().getClass() == x.getClass()

will be true, but these are not absolute requirements. While it is typically the case that:

x.clone().equals(x)

will be true, and this is also not an absolute requirement.

Let me explain what these rules mean, "x.clone() != x" means, the clones object should not hold the same memory address of the original object. And "x.clone().getClass() == x.getClass()" means, the cloned object and the original object should be of the same type. Well again why its said that these are not absolute requirements because, when you shallow copy the object and if the object hold any references to someother object, then the references are copied. Yes, if you go for a deep copy, the above two rules will satisfy. Now lets see the thrid one, "x.clone().equals(x)" means the cloned object data should be equal to the original one but again this is not absolute requirement. The cloned copy data or the original object data can change any time.


How do you implement cloning in java?

Now, getting into it. In java, to do cloning, you must implement clone() method. Lets start with an example code.


public class Color {

    private String color;

    public Color(String c){
        this.color = c;
    }

    //getters and setters for the fields should go here........
}

public class ColoredCircle implements Cloneable {

    private int centerX;
    private int centerY;
	private Color color;

	public ColoredCircle(int x, int y, Color c){
	    this.centerX = x;	
		this.centerY = y;
		this.color = c;
	}

    public Object clone() {
        try {
            return (ColoredCircle)super.clone();
        }
        catch (CloneNotSupportedException e) {
            // This should never happen
        }
    }

    //getters and setters for the fields should go here........
}

public class CloneMain {

    public static void main(String [] args) {

		Color c = new Color("RED");
        ColoredCircle c1 = new ColoredCircle(200,200,c);
        ColoredCircle c2 = c1.clone();
    }
}

To implement cloning in your class, first, make your object implement Cloneable and then set up the implementation of clone() method with a try-catch block for CloneNotSupportedException. Ok. What will happen when you implement this way? Since the class implements the "Cloneable" interface, it registers itself to be ready for copying itself. So when the object calls "clone()" method, a copy of the object is returned. If you observe here, we are calling "super.clone()" inside clone() method. Because clone() is declared in class Object, it is inherited by every Java object and hence calling super.clone() copies your superclass's fields, and makes bitwise copies of your fields. This is nothing but shallow copy which means when you copy the "ColoredCircle" using clone() method, the fields x and y are copied perfectly with values but field "color" is copied by reference. So any changes you make to the color of the original object will be reflected in the copied object and vice versa. The solution for this is deep copy. Change the Color class to implement "Cloneable" interface and clone() method and call the clone() method of color object inside the clone() method of the ColoredCircle object. Look at the changed Color class and ColoredCircle class below.


public class Color implements Cloneable{

    private String color;

    public Color(String c){
        this.color = c;
    }

    public Object clone() {
        try {
            return (Color)super.clone();
        }
        catch (CloneNotSupportedException e) {
            // This should never happen
        }
    }

    //getters and setters for the fields should go here........
}

public class ColoredCircle implements Cloneable {

    private int centerX;
    private int centerY;
    private Color color;

    public ColoredCircle(int x, int y, Color c){
        this.centerX = x;	
        this.centerY = y;
        this.color = c;
    }

    public Object clone() {
        ColoredCircle coloredCircle = null;
        try {
            coloredCircle = (ColoredCircle)super.clone();
        }
        catch (CloneNotSupportedException e) {
            // This should never happen
        }
        coloredCircle.color = (Color) color.clone();
        return coloredCircle;
    }

    //getters and setters for the fields should go here........
}


To know more about Shallow Copy and Deep Copy, check it out here or go to "Deep Copy/Shallow Copy" article. Ok. Now lets get back to know more about Cloneable interface. The Cloneable interface is a marker interface which means it dont have any methods. So after you implement Cloneable interface, if you dont write clone() method in your class,nothing will happen. The purpose of Cloneable interface is to tell JVM that this class is eligible for cloning. Note that the class Object doesn't implement Cloneable interface, hence if you call the Object class "clone()" method without implementing Cloneable interface, a CloneNotSupportedException will be thrown.

Generally when you invoke clone() method in your object, it should either:

One more point. It is not mandatory to implement clone() method in your class when you want to clone the object. If you dont, since the clone() method in class Object is declared protected, only subclasses and members of the same package will be able to invoke clone() on the object. Thats why to enable any class in any package to access the clone() method, you'll have to override it and declare it public.

Let me tell you couple of gotchas with Cloneable interface

1. When you dont know whether you can call the clone() method of a particular class as you are not sure if it is implemented in that class, you can check with checking if the class is instance of "Cloneable" interface as below.


if(obj1 instanceof Cloneable){
    obj2 = obj1.clone();
}

2. As Cloneabe interface is a marker interface (dont have any methods in it), you can never cast an object to Cloneable and call clone() method. Check below.


//Dont do this. Cloneabe dont have any methods
obj2 = (Cloneable)obj1.clone();

Well, clone has its own problems

First one is that no constructor is called on the object being cloned. As a result, it is your responsibility, to make sure all the members have been properly set. Lets consider a class keeping track of the total number of objects of that type, using a static int member. Generally in the constructors you would increase the count. But, when you clone the object, since no constructor is called, the count will not get updated and wont reflect the correct number of objects.

Second one is, if the class has final fields, these can�t be given a value in the clone method. This leads to problems with properly initializing the object�s final fields. If the final field is referring to some internal state of the object, then the cloned object ends up sharing the internal state and this surely is not correct for mutable objects.


The solution for these problems is "copy-constructor".

What is copy-constructor?

A copy constructor is one that takes object of its own type as a single parameter.


public class Person
{
    private Car car;
    private String name;
    public Person(Car c, String n)
    {
        car = c; 
        name = n;
    }
    public Person(Person p)
    {
        name = p.name;
        car = new Car(p.car);
        // we assume we have a copy constructor for Car
    }
    public String toString()
    {
        return "This is person has " + car;
    }
}

public class Car
{
    public Car() {}
}

public class CopyConstructorMain {

    public static void main(String [] args) {

        Person person1 = new Person(new Car(), "Ben");
        Person person2 = new Person(person1);
        System.out.println(person1);
        System.out.println(person2);
    }
}

Output is:
----------
This is person has Car@4edbb0
This is person has Car@3f75e0

In this example, in class Person, "public Person(Person p)" is the copy constructor. This is used to create a copy of person1 object. The copy constructor worked perfectly fine in this exmaple. But if the variable "car" in Person class is actually an instance of a subclass � then you will get the wrong answer; what is called a slice. Check below example and you will understand what I meant by a problem. Lets say you have a subclass of Car - "Mitsubishi".


public class Mitsubishi extends Car
{
    public Mitsubishi() {}
}

public class CopyConstructorMain {

    public static void main(String [] args) {

        Person person1 = new Person(new Mitsubishi(), "Ben");
        Person person2 = new Person(person1);
        System.out.println(person1);
        System.out.println(person2);
    }
}

Output is:
----------
This is person has Mitsubishi@2e4560
This is person has Car@3f34d4

The expected answer in this example is "Mitsubishi" object for both Person objects but you got the wrong answer. One way, to fix this is check the instance of the object and type cast accordingly.


public Person(Person p)
{
    name = p.name;
    if (p.car instanceof Mitsubishi)
       car = new Mitsubishi((Mitsubishi)p.car);
    else
       car = new Car(p.car);
}

Now this is not a perfect fix, as the code needs to be modified if another type of Car (a derived class of Car) is introduced in the system.

A good way to copy an object is to let the object do it. In other words, rather than the Person creating a Car (using another instance of Car), i.e., new Car(car);, why not ask the car to make a copy of itself?

public class Car
{
    public Car() {}
    public Car(Car c) {...} // Assume proper copying of the Car
}

public class Mitsubishi extends Car
{
    public Mitsubishi() {}
    public Mitsubishi(Mitsubishi m) {...}
}

And the best way to fix this is combine copy-constructor and clone. This will work perfectly.


public class Person implements Cloneable
{
    private final Car car;
    private String name;
    public Person(Car c, String n)
    {
        car = c; 
        name = n;
    }
    public Person(Person p)
    {
        Car instCar = null;
		try
		{
			instCar = (Car) p.car.clone();
		}
		catch(CloneNotSupportedException e) {}
		car = instCar;
		name = p.name;
    }

	public Object clone()
	{
		return new Person(this);
	}

    public String toString()
    {
        return "This is person has " + car;
    }
}





blog comments powered by Disqus