Skip to main content

Copying objects – Java Clonable interface



We can assign reference of an object to another, provided each of them satisfies an “is-a” relationship or of same type. For example, a Dog object can hold the reference of another Dog object regardless both have different states. Similarly an Animal object can hold the reference of a Dog or Cat object, if they satisfies an “is-a” relationship. But hold on, these assignments do not help you to create a duplicate copy of the object. It’s nothing but different pointers pointing to the same memory location.

Java provides API to clone an object. Using this API one can get a copy of an object to another. To achieve this, proposed class should implement Clonable interface (else JVM will throw CloneNotSupportedException during runtime). The rationale behind cloning is to get an independent copy of an object. The Object class has a clone() method which takes care of this operation. This method is protected by nature and returns an Object, when called.  You can call this method on an object if you intend to get a copy of that object; however you have to make sure that the class of the object implements a Clonable interface. The Clonable interface is a marker interface. A marker interface by definition is an empty interface that does not contain any method and used to serve special purposes. Clonable interface tells the JVM that the caller may ask to give a new copy of an object of this class, so be prepared or in other words this class can be cloned by the caller. Is not it pretty! Look at the below example,
I have created a play list where I can add my favorite songs, this class is Clonable so that if I want to get a copy of this play list I can get that easily and save that somewhere else using some serializable class (a class whose objects can be saved to secondary memory, to achieve that I have make this class serializable. Just forget it for now!).

public class PlayList implements Cloneable {
    private ArrayList<Song> songs;

    public PlayList() {
        this.songs = new ArrayList<Song>();
    }

    public String displaySongs() {
        return songs.toString();
    }

    public void addSongs(Song song) {
        songs.add(song);
    }

    public void removeSong(Song song) {
        songs.remove(song);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

I have overridden the clone() method and I just called the super class to invoke it. If you do not override this method you may not be able to clone any object of this class, because if you try so compiler will not allow you to do that.

public class Song {
    private String name;

    public Song(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return getName();
    }

    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Song) {
            return ((Song) obj).getName().equals(name);
        }
        return false;
    }
}

I think we are good now and can start writing the main method to run the application with some songs added into the play list. I have created an original play list (playList) and copied that list to another play list (copied_PlayList). Isn’t it awesome, I have two play lists now.

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Song song1 = new Song("Hotel California");
        Song song2 = new Song("Mama I'm coming home");
        Song song3 = new Song("November Rain");

        PlayList playList = new PlayList();
        playList.addSongs(song1);
        playList.addSongs(song2);
        playList.addSongs(song3);
        System.out.println("Original List: " + playList.displaySongs());

        PlayList copied_PlayList = (PlayList) playList.clone();
        System.out.println("Copied List: " + copied_PlayList.displaySongs());
    }
}

And here it goes; I can see both lists when I run the program,
               
Original List: [Hotel California, Mama I'm coming home, November Rain]
Copied List: [Hotel California, Mama I'm coming home, November Rain]

Let me add one more song into the original list and see, whether I get two different list or not,

Song song4 = new Song("Sweet child of mine");
              playList.addSongs(song4);
              System.out.println("Original List: " + playList.displaySongs());
              System.out.println("Copied List: " + copied_PlayList.displaySongs());

When I run the program I see below output,

Original List: [Hotel California, Mama I'm coming home, November Rain, Sweet child of mine]
Copied List: [Hotel California, Mama I'm coming home, November Rain, Sweet child of mine]

What the hell, that’s not so awesome. I am getting the same play list twice, which I do not want. Any modification to the original list should not affect the copied list. It’s just a copied list from the original old list.

I think I should cool down and understand the principles behind cloning an object. When an object is cloned it can be cloned using two principles or techniques,
1.       Swallow copy
2.       Deep Copy

Oh boy, I should have thought of the before, I have to change the application now. Anyway let me tell you what each means,

1.       Swallow copy, It says if you are cloning an object JVM will copy the structure not the reference variables, meaning it will not copy the whole object graph unless you are using some immutable objects. The reference variables of both the objects will refer to the same variable references.

In my example, Play list class has an array list (songs) reference that holds the entire song objects that I have added so far. As per the principle of swallow copy this list will be shared among the original and the copied list, hence any changes to this list will be reflected to both the objects, and that’s what we saw. So, looks like we just implemented swallow copy. 

2.       Deep copy, It’s the opposite of swallow copy. Deep copy helps you to get a completely new copy of an object. Look at the below Song list class, inside the clone method I have created a new object of Song list and I have added the song list.

@Override
    protected Object clone() throws CloneNotSupportedException {
        PlayList playList = new PlayList();
        playList.songs = new ArrayList<Song>();
        playList.songs.addAll(this.songs);
        return playList;
    }
 
If I run the main program now I can see below,

Original List: [Hotel California, Mama I'm coming home, November Rain]
Copied List: [Hotel California, Mama I'm coming home, November Rain]
Original List: [Hotel California, Mama I'm coming home, November Rain, Sweet child of mine]
Copied List: [Hotel California, Mama I'm coming home, November Rain]

Phew! that was not that hard. So we have to remember two things here, Swallow copy and Deep copy before designing a class which is Clonable. It’s all depends on the requirement; however we should be able to choose the best one as per our need. Keep this in mind that primitive types and immutable objects are always deep copied under any circumstances, if they are not forced to change.

Comments

Popular posts from this blog

Spring: Method Injection

This is useful when a Singleton bean need to use a non-singleton bean. Sometime your application may need to collaborate a prototype bean with a singleton bean to satisfy your business logic. That is your singleton bean is dependent on a prototype bean. Let’s consider three beans Customer Sales Person Product A customer may ask a sales Person to show different type of products from the repository. Let’s assume you have gone to a garment shop to buy a new shirt for the lucky date with your new girlfriend. So, it’s a tough choice and you may like to try different colors and styles and finally you will choose one. So, if we describe the above situation in the form of business logic inside one of your module, it will look like this, The sales Person should show a new product every time he requests. Let’s assume Customer and Sales Person to be singleton bean in your Spring container and Product as prototype. But based on bean life-cycle a prototype bean can not be injec...

JUnit Rule : Creating Temporary Folder

I was surprised to see this beautiful feature in JUnit and it helped to ease to lots of constrains I face while writing JUnit tests. I basically follow TDD and as you guys know we focus more on writing tests, hence it is necessary to use some shortcuts availed by the tools like JUnit to make the process fast. Recently I had an issue where I had to create and delete a file before and after every test executes. I did that using @Before and @After annotation of Junit and it worked, however I was looking for more of a generic way to do this at one place. As I started googling I came across this post, which is amazing,  After reading the block I know how I can generalize my creating and deleting of a temporary file or folder (I decided to go with a temporary folder and a file inside it, which looks more readable and oganized). The JUnit class: public class TemporaryFolderTestCase { @Rule public TemporaryFolder temporaryFolder = new TemporaryF...