Skip to main content

Java Cloning - Copy Constructor versus Cloning

In my previous article Java Cloning and Types of Cloning (Shallow and Deep) in Details with Example, I have discussed Java Cloning in details and answered questions about how we can use cloning to copy objects in Java, what are two different types of cloning (Shallow & Deep) and how we can implement both of them, if you haven’t read it please go ahead.

In order to implement cloning, we need configure our classes to follow below steps
  • Implement Cloneable interface in our class or its superclass or interface,
  • Define clone() method which should handle CloneNotSupportedException (either throw or log),
  • And in most cases from our clone() method we call the clone() method of the superclass.
Java Cloning versus Copy Constructor

And super.clone() will call its super.clone() and chain will continue until call will reach to clone() method of the Object class which will create a field by field mem copy of our object and return it back.

Like everything Cloning also comes with its advantages and disadvantages. However, Java cloning is more famous its design issues but still, it is the most common and popular cloning strategy present today.

Advantages of Object.clone()

Object.clone() have many design issues but it is still the popular and easiest way  of copying objects, Some advantages of using clone() are
  • Cloning requires very less line of code, just an abstract class with 4 or 5 line long clone() method but we will need to override it if we need deep cloning.
  • It is the easiest way of copying object specially if we are applying it to an already developed or an old project. We just need to define a parent class, implement Cloneable in it, provide the definition of clone() method and we are ready every child of our parent will get the cloning feature. 
  • We should use clone to copy arrays because that’s generally the fastest way to do it.
  • As of release 1.5, calling clone on an array returns an array whose compile-time
    type is the same as that of the array being cloned which clearly means calling clone on arrays do not require type casting.

Disadvantages of Object.clone()

Below are some cons due to which many developers don't use Object.clone()
  • Using Object.clone() method requires us to add lots of syntax to our code like implement Cloneable interface, define clone() method and handle CloneNotSupportedException and finally call to Object.clone() and cast it our object.
  • Cloneable interface lacks clone() method, actually, Cloneable is a marker interface and doesn’t have any method in it and still, we need to implement it just to tell JVM that we can perform clone() on our object.
  • Object.clone() is protected so we have to provide our own clone() and indirectly call Object.clone() from it.
  • We don’t have any control over object construction because Object.clone() doesn’t invoke any constructor.
  • If we are writing clone method in a child class e.g. Person then all of its superclasses should define clone() method in them or inherit it from another parent class otherwise super.clone() chain will fail.
  • Object.clone() support only shallow copy so reference fields of our newly cloned object will still hold objects which fields of our original object was holding. In order to overcome this, we need to implement clone() in every class whose reference our class is holding and then call their clone them separately in our clone() method like in below example.
  • We can not manipulate final fields in Object.clone() because final fields can only be changed through constructors. In our case, if we want every Person objects to be unique by id we will get the duplicate object if we use Object.clone() because Object.clone() will not call the constructor and final final id field can’t be modified from Person.clone().
class City implements Cloneable {
private final int id;
private String name;
public City clone() throws CloneNotSupportedException {
return (City) super.clone();
}
}

class Person implements Cloneable {
public Person clone() throws CloneNotSupportedException {
Person clonedObj = (Person) super.clone();
clonedObj.name = new String(this.name);
clonedObj.city = this.city.clone();
return clonedObj;
}
}

Because of above design issues with Object.clone() developers always prefer other ways to copy objects like using
  • BeanUtils.cloneBean(object) creates a shallow clone similar to Object.clone().
  • SerializationUtils.clone(object) creates a deep clone. (i.e. the whole properties graph is cloned, not only the first level), but all classes must implement Serializable.
  • Java Deep Cloning Library offers deep cloning without the need to implement Serializable.
All these options require the use of some external library plus these libraries will also be using Serialization or Copy Constructors or Reflection internally to copy our object. So if you don’t want to go with above options or want to write our own code to copy the object then you can use
  1. Serialization
  2. Copy Constructors

Serialization

I have discussed in 5 Different ways to create objects in Java with Example how we can create a new object using serialization. Similarly, we can also use serialization to copy an object by first Serialising it and again deserializing it like it is done below or we can also use other APIs like JAXB which supports serialization.

public Person copy(Person original) {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"));
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"))) {

// Serialization
out.writeObject(original);

//De Serialization
return (Person) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e); // log exception or throw it by your own way
}
}

But serialization is not solving any problem because we will still not be able to modify the final fields, still don’t have any control on object construction, still needs to implement Serializable which is again similar to Cloneable. Plus serialization process is slower then Object.clone().

Copy Constructors

This method copying object is most popular between developer community it overcomes every design issue of Object.clone() and provides better control over object construction

public Person(Person original) {
this.id = original.id + 1;
this.name = new String(original.name);
this.city = new City(original.city);
}

Advantages of copy constructors over Object.clone()

Copy constructors are better than Object.clone() because they
  • Don’t force us to implement any interface or throw any exception but we can surely do it if it is required.
  • Don’t require any casts.
  • Don’t require us to depend on an unknown object creation mechanism.
  • Don’t require parent class to follow any contract or implement anything.
  • Allow us to modify final fields.
  • Allow us to have complete control over object creation, we can write our initialization logic in it.
By using Copy constructors strategy, we can also create conversion constructors which can allow us to convert one object to another object e.g. ArrayList(Collection<? extends E> c) constructor generates an ArrayList from any Collection object and copy all items from Collection object to newly created ArrayList object.


Comments

Post a Comment

Popular posts from this blog

Why an outer Java class can’t be static

In a previous blog , I talked about why we can not define an outer class using private or protected keywords. If you have not read it, please go ahead and give it a look. I this article I will talk what is the use of the static keyword, why an outer Java class can’t be static, why it is not allowed in Java to define a static outer class. In order to understand that first, we need to understand what is the static keyword used for, what purpose it solves and how does it works. What does static keyword do Every Java programmer knows that if we need to define some behavior (method) or state (field) which will be common to all objects we define it as static. Because static content (behavior or state) does not belong to any particular instance or object, it will common to all objects and all objects are free to change any static field and every change will be visible to every object. We do not need to create any object of the class to access a static field or method, we can directly refer a

Why Single Java Source File Can Not Have More Than One public class

According to Java standards and common practices we should declare every class in its own source file. And even if we declare multiple classes in the single source file (.java) still each class will have its own class file after compilation. But the fact is that we can declare more than one class in a single source file with below constraints, Each source file should contain only one public class and the name of that public class should be similar to the name of the source file. If you are declaring the main method in your source file then main should lie in that public class If there is no public class in the source file then main method can lie in any class and we can give any name to the source file. If you are not following 1st constraint then you will receive a compilation error saying “ The public type A must be defined in its own file ”.  While if you are not following the second constraint you will receive an error “ Error: Could not find or load main class User ” after exec

Creating objects through Reflection in Java with Example

In Java, we generally create objects using the new keyword or we use some DI framework e.g. Spring to create an object which internally use Java Reflection API to do so. In this Article, we are going to study the reflective ways to create objects. There are two methods present in Reflection API which we can use to create objects Class.newInstance() → Inside java.lang package Constructor.newInstance() → Inside java.lang.reflect package However there are total 5 ways create objects in Java, if you are not aware of them please go through this article 5 Different ways to create objects in Java with Example . Both Class.newInstance() and java.lang.reflect.Constructor.newInstance() are known as reflective methods because these two uses reflection API to create the object. Both are not static and we can call earlier one on a class level object while latter one needs constructor level object which we can get by using the class level object. Class.newInstance() The Class class is the mo