This post is a continuation to my previous article on Default Copy Constructor in Java. If you haven’t read through it, I would suggest you to read that article first before going through this one.
Today I am going to discuss about the temporary solution to copying objects in Java using clone method in Object class.
Recap on the Problem
The problem we have faced regarding our previous solution is maintainability.
Let’s say we have a requirement to add another new property to the Result class, namely Grade. The hassles of adding Copy Constructor to each and every class has to be endured.
Let’s consider another example. If we have several different kinds of Result types then in Student copy constructor we have to have an instanceof test on each and every type of Result instance which eventually makes the code less readable, error-prone and not-extensible.
The previous solution also violates Open-Closed Principle and hence it is not advisable.
Let’s start with some more concrete types of Results.
Here, in this class, we needed to add all the different instanceof tests to check for actual Result instance before delegating it to the copy constructor.
Otherwise, we will end up confronting the same problem of Shallow Copy.
Solution - Clone
In the Object class, we have a method clone which we can utilize in case of copying objects.
In the aforementioned class, we have inherited the clone method and implemented it to return a new Result instance by copying the properties.
In Student class, we have inherited the clone method and implemented it accordingly by copying the properties. But you can see that I have invoked clone method on the contained Result instance. Due to this, we achieve Deep Copying so that we make sure each and every newly cloned Student object will contain a newly cloned Result instance.
Now you might be wondering about the subtle differences in these two solutions - one with clone method and one with Default Copy Constructor.
The most noticeable difference is that to make use of clone method, our Student and Result POJO extended Cloneable interface.
Now let’s talk about the actual differences in using clone method.
Let’s consider, we have a subtype of Result class as follows.
According to the definition of clone method in Result class, it will automatically handle the runtime type of any Result type and it will invoke the respective clone method from the specific subtype of Result class. This occurs because methods are polymorphic in nature.
In the previous solution, we introduced Default Copy Constructor which used to create respective objects using new keyword. In Java, new is not at all polymorphic in nature and that’s why we had to introduce the instanceof type check to verify the runtime type of any specific Result instance.
Now if we use clone the aforementioned way, we would be able to deep copy objects.
Do we really have any problem in using clone method?
We can deep copy objects, it’s polymorphic as well. Then what is the problem?
Let’s now change our Result POJO a bit.
Result POJO - Modified
The aforementioned code has been slightly modified by introducing identifier property to the Result class. The clone method has been modified to cope up with the recent changes.
Now, if we make our identifier property constant, then the clone method will report a compilation error as it wouldn’t be able to reassign a value to a constant.
The following assignment in the clone method will not work in case we change the id to a constant.
We are facing problems with the Default Copy Constructor as well as clone method. So, what would come to rescue us?
I think we can have a look at the solution in my soon-to-come post.