Introduction

Like C++, Java also supports copy constructor. But, unlike C++, Java doesn’t create a default copy constructor. Copy constructor is helpful when we want to copy an object that is heavy to instantiate. While writing copy constructor it’s very important to perform deep copy so that both the objects are detached. However in some cases where you don’t mind the change in object data, then you can also go for shallow copy. Copy Constructors can take only one parameter, which is a reference of the same class.

With Copy Constructors we can achieve both Shallow Copy and Deep Copy. If a class has any references to other objects as fields, then only references of those objects are copied into clone object, a fresh copy of those objects are not created. We need to use the new operator inside the Copy Constructor for it to be deep copied. Primitives types are by default deep copied we can change the values.

// Shallow Copy Constructor Example
public class Address
{
  public String state;
  
  public Address(String state)
  {
    this.state = state;
  }

  public Address(Address address)
  {
    this.state = address.state;
  }
}

public class Person
{
  public int x;
  
  public Address address;

  public Person(int x, Address address)
  {
    this.x       = x;
    this.address = address;
  }
  
  // Copy Constructor
  public Person(Person p)
  {
    this.x       = p.x;
    this.address = p.address; // Shallow Copying
    // this.address = new Address(p.address); //Deep Copying
  }

  public static void main(String[] args)
  {
    Address address = new Address("TN");
    
    Person p1 = new Person(2,address);
    
    // Invokes copy constructor
    Person p2 = new Person(p1);
    
    System.out.println(p1.address.state);  // Output: TN
    System.out.println(p2.address.state);  // Output: TN
    
    // Change the state of P2 object
    p2.address.state = "Karnataka";
    
    System.out.println(p1.address.state); // Output: Karnataka
    System.out.println(p2.address.state); // Output: Karnataka
  }
}

 

Advantages

Benifits of copy constructors over Object.clone()

  • Unlike clone() method, Copy Constructors will not force us to implement the Cloneableor Serializable interface
  • It gives us the complete control over object copy, we can even mix both Deep Copy and Shallow Copy for different attributes of the class.
  • clone() method throws CloneNotSupportedException whenever the class does not implement Cloneable interface, Copy Constructor will not be throwing these Exceptions.
  • Typecasting is required as the clone() method returns Object type, whereas Copy Constructor does not need such typecasting.
  • Copy Constructor will let us change the value of a final attribute whereas clone() method will throw compilation error when you try to change a final field.

Uses

Let’s say we redefined getYear, so that it doesn’t use a copy constructor. It would look like this:

public Year getYear(){
  // Private member of the class
  return leapYear;
}

The problem here is that a reference to the private instance variable ‘leapYear’ is being returned. This means that anyone could declare a SomeClass object, call the accessor method getYear() with that object and assign the return value to a Year object. The danger with this is that the Year object now holds a reference to what was supposed to be a private instance variable (leapYear), thereby violating its privacy. This is shown below:

public class SomeClass
{
  public Year getYear()
  {
    return leapYear;
  }
}

// Suppose the following is done in some other class:
SomeClass someObj = new SomeClass();

// yrObj now has a reference to leapYear. It caan now change
// the contents of the private instance variable leapYear
Year yrObj = someObj.getYear();

By using a copy constructor in the definition of getYear(), a separate Year object is created entirely. This object has the same values stored in the instance variables as the original leapYear object, but with its own address space. This way the original leapYear is safe.