Difference between Deep and Shallow Copy in Java Object Cloning

Shallow copy and deep copy is related with cloning process so before go into the deep of shallow and deep copy we need to understand what is clone in java. Clone is nothing but the process of copying one object to produce the exact object, which is not guaranteed. We all know in Java object is referred by reference we can not copy one object directly to another object. So we have a cloning process to achieve this objective. Now one question arises in mind why we need this process so the answer is whenever we need a local copy of the object to modify the object in some method but not in the method caller.  

So we can define Cloning as “create a copy of object  .I think now we are somehow clear about cloning but there  is more to it depending on how we are doing this copy, we can divide cloning into two types.
  • Shallow Copy
  • Deep Copy
Before going into the deep of shallow and deep copy we need to understand how we achieve cloning in java.


How to Clone Objects in Java?

Difference between deep cloning vs shallow cloning in JavaIn Java, everything is achieved through class, object, and interface.By default, no Java class support cloning but Java provide one interface called Cloneable, which is a marker interface and by implementing this interface we can make the duplicate copy of our object by calling clone() method of  java.lang.Object class. 



This Method is protected inside the object class and Cloneable interface is  a marker interface and this method also throw  CloneNotSupportedException if we have not implemented this interface and try to call clone() method of Object class. 

By default any clone() method gives the shallow copy of the object i.e. if we invoke super.clone() then it’s a shallow copy but if we want to deep copy we have to override the clone() method and make it public and give own definition of making copy of object. Now we let’s see  what is shallow and deep copy of object in Java programming language.


1. Shallow Copy in Java

Whenever we use default implementation of clone method we get shallow copy of object means it create new instance and copy all the field of object to that new instance and return it as object type we need to explicitly cast it back to our original object. 

This is shallow copy of the object. clone() method of the object class support shallow copy of the object. If the object contains primitive as well as non primitive or reference type variable In  shallow copy, the cloned object also refers to the same object to which the original object refers as only the object references gets copied and not the referred objects themselves. 

That's why the name shallow copy or shallow cloning in Java. If only primitive type fields or Immutable objects are there then there is no difference between shallow and deep copy in Java.


2. Deep Copy in Java

Whenever we need own meaning of copy not to use default implementation we call it as deep copy, whenever we need deep copy of the object we need to implement according to our need. So for deep copy we need to ensure all the member class also implement the Cloneable interface and override the clone() method of the object class. 

After that we override the clone() method in all those classes even in the classes where we have only primitive type members otherwise we would not be able to call the protected clone() method of Object class on the instances of those classes inside some other class. It’s typical restriction of the protected access.



Difference between Shallow and Deep Copy in Java

I think now we know what is deep and shallow copy of object in Java, let see some difference between them so that we can get some more clarity on them.
  •  When we call Object.clone(), this method performs a shallow copy of object, by copying data field by field, and if we override this method and by convention first call super.clone(), and then modify some fields to "deep" copy, then we get deep copy of object. This modification is done to ensure that original and cloned object are independent to each other.

  • In shallow copy main or parent object is copied, but they share same fields or children if fields are modified in one parent object other parent fields have automatic same changes occur,but in deep copy this is not the case.

  • If our parent object contains only primitive value then shallow copy is good for making clone of any object because in new object value is copied but if parent object contains any other object then only reference value is copied in new parent object and both will point to same object so in that case according to our need we can go for deep copy.

  • Deep copy is expensive as compare to shallow copy in terms of object creation, because it involves recursive copying of data from other mutable objects, which is part of original object.

This is all about deep copy and shallow copy of objects in Java. Now the question comes when we use shallow copy and when go for deep copy, so the answer would be simple that if the object has only primitive fields or Immutable objects, then obviously we will go for shallow copy, but if the object has references to other mutable objects, then based on the requirement, shallow copy or deep copy can be chosen. 

This means if the references are not modified anytime, then there is no point in going for deep copy, We can go for shallow copy. But if the references are modified often, then you need to go for deep copy. Again there is no hard and fast rule, it all depends on the requirement.

Hope this article will help to make clear about deep and shallow copy of cloning process.

Related Java Interview Questions articles from Java67 Blog
Difference between ConcurrentHashMap vs HashMap in Java

15 comments:

  1. Cloning is flawed in Java, don't use Cloning. If you want to create multiple clone of your object, consider using Copy Constructor. It's easy to implement clone() method wrong than right.

    ReplyDelete
    Replies
    1. Then what is the right way to create clone or simply a deep copy of an Object?

      Delete
  2. Thanks . It Would have better if you had given an example to explain.

    ReplyDelete
  3. tks ~! very nice post ~~ it's better if u give some exapmle codes .

    ReplyDelete
  4. Great post (Y). the dependency of mutable objects while copying is very well explained.

    ReplyDelete
  5. can you provide code sample

    ReplyDelete
  6. If the object contains primitive as well as non primitive or reference type variable In shallow copy, the cloned object also refers to the same object to which the original object refers as only the object references gets copied and not the referred objects themselves.


    This one was very confusing.
    So the basic difference between shallow and deep copy is.
    Shallow copy copies the primitive values as it is but for reference type it copies reference to the object and doesnt create the new object.

    Meanwhile in deep copy you can override the clone() method to copy the exact values in the new object you create which is deep copy

    ReplyDelete
  7. Nice explanation! Hats off to the author.

    ReplyDelete
  8. want example code also....???????

    ReplyDelete
  9. Excellent explanation. Thanks for your valuable time.

    Dr. A A Moiz Qyser

    ReplyDelete
  10. Thanks for such and detailed explanation...
    Here i am copying sample example,

    ########## Deep Copy ###########
    public class Main {

    public static void main(String[] args) throws Exception {
    AccountDetails accountDetails = new AccountDetails("1111111111", "222");
    Account acc = new Account("Old Name", "3333333333", accountDetails);
    System.out.println("Original Acc Object : " + acc);

    Account clone = (Account) acc.clone();
    System.out.println("Cloned Acc Object : " + clone);

    acc.setName("New Name");
    acc.setAccountNumber("000000000");
    acc.getAccountDetails().setAtmCardNumber("888888888");
    acc.getAccountDetails().setCvv("999");

    System.out.println("Modified Acc Object :" + acc);

    /*
    * modifying original Account object does not affects the cloned object
    * in deep copy
    */
    System.out.println("Cloned object after Acc modification : " + clone);
    }
    }

    class Account implements Cloneable {
    private String name;
    private String accountNumber;
    private AccountDetails accountDetails;

    public Account(String name, String accountNumber,
    AccountDetails accountDetails) {
    super();
    this.name = name;
    this.accountNumber = accountNumber;
    this.accountDetails = accountDetails;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getAccountNumber() {
    return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
    this.accountNumber = accountNumber;
    }

    public AccountDetails getAccountDetails() {
    return accountDetails;
    }

    public void setAccountDetails(AccountDetails accountDetails) {
    this.accountDetails = accountDetails;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    Account clone = (Account) super.clone();
    clone.setAccountDetails((AccountDetails) clone.getAccountDetails()
    .clone());
    return clone;
    }

    @Override
    public String toString() {
    return name + " " + accountNumber + " " + accountDetails;
    }
    }

    class AccountDetails implements Cloneable {
    private String atmCardNumber;
    private String cvv;

    public AccountDetails(String atmCardNumber, String cvv) {
    super();
    this.atmCardNumber = atmCardNumber;
    this.cvv = cvv;
    }

    public String getAtmCardNumber() {
    return atmCardNumber;
    }

    public void setAtmCardNumber(String atmCardNumber) {
    this.atmCardNumber = atmCardNumber;
    }

    public String getCvv() {
    return cvv;
    }

    public void setCvv(String cvv) {
    this.cvv = cvv;
    }

    @Override
    public String toString() {
    return atmCardNumber + " " + cvv;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
    }
    }

    ReplyDelete
  11. ######### Example of Shallow Copy ################

    public class Main {

    public static void main(String[] args) throws Exception {
    AccountDetails accountDetails = new AccountDetails("1111111111", "222");
    Account acc = new Account("Old Name", "3333333333", accountDetails);
    System.out.println("Original Acc Object : " + acc);

    Account clone = (Account) acc.clone();
    System.out.println("Cloned Acc Object : " + clone);

    acc.setName("New Name");
    acc.setAccountNumber("000000000");
    acc.getAccountDetails().setAtmCardNumber("888888888");
    acc.getAccountDetails().setCvv("999");

    System.out.println("Modified Acc Object :" + acc);

    /*
    * modifying original Account object affects the cloned object in
    * shallow copy
    */
    System.out.println("Cloned object after Acc modification : " + clone);
    }
    }

    class Account implements Cloneable {
    private String name;
    private String accountNumber;
    private AccountDetails accountDetails;

    public Account(String name, String accountNumber,
    AccountDetails accountDetails) {
    super();
    this.name = name;
    this.accountNumber = accountNumber;
    this.accountDetails = accountDetails;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getAccountNumber() {
    return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
    this.accountNumber = accountNumber;
    }

    public AccountDetails getAccountDetails() {
    return accountDetails;
    }

    public void setAccountDetails(AccountDetails accountDetails) {
    this.accountDetails = accountDetails;
    }

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

    @Override
    public String toString() {
    return name + " " + accountNumber + " " + accountDetails;
    }
    }

    class AccountDetails {
    private String atmCardNumber;
    private String cvv;

    public AccountDetails(String atmCardNumber, String cvv) {
    super();
    this.atmCardNumber = atmCardNumber;
    this.cvv = cvv;
    }

    public String getAtmCardNumber() {
    return atmCardNumber;
    }

    public void setAtmCardNumber(String atmCardNumber) {
    this.atmCardNumber = atmCardNumber;
    }

    public String getCvv() {
    return cvv;
    }

    public void setCvv(String cvv) {
    this.cvv = cvv;
    }

    @Override
    public String toString() {
    return atmCardNumber + " " + cvv;
    }

    }

    ReplyDelete
  12. What a great explanation. Thanks a lot

    ReplyDelete

Feel free to comment, ask questions if you have any doubt.