Java Copy Constructor

1. Introduction

A copy constructor in a Java class is a constructor that creates an object using another object of the same Java class.

That’s helpful when we want to copy a complex object that has several fields, or when we want to make a deep copy of an existing object.

2. How to Create a Copy Constructor

To create a copy constructor, we can first declare a constructor that takes an object of the same type as a parameter:

public class Employee {
    private int id;
    private String name;
  
    public Employee(Employee employee) {
    }
}

Then, we copy each field of the input object into the new instance:

public class Employee {
    private int id;
    private String name;
    
    public Employee(Employee employee) {
        this.id = employee.id;
        this.name = employee.name;
    }
}

What we have here is a shallow copy, which is fine since all of our fields – an int and a String in this case – are either primitive types or immutable types.

If the Java class has mutable fields, then we can instead make a deep copy inside its copy constructor. With a deep copy, the newly created object is independent of the original one because we create a distinct copy of each mutable object:

public class Employee {
    private int id;
    private String name;
    private Date startDate;

    public Employee(Employee employee) {
        this.id = employee.id;
        this.name = employee.name;
        this.startDate = new Date(employee.startDate.getTime());
    }
}

3. Copy Constructor vs. Clone

In Java, we can also use the clone method to create an object from an existing object. However, the copy constructor has some advantages over the clone method:

  1. The copy constructor is much easier to implement. We do not need to implement the Cloneable interface and handle CloneNotSupportedException.
  2. The clone method returns a general Object reference. Therefore, we need to typecast it to the appropriate type.
  3. We can not assign a value to a final field in the clone method. However, we can do so in the copy constructor.

4. Inheritance Issues

Copy constructors in Java are not inheritable by subclasses. Therefore, if we try to initialize a child object from a parent class reference, we will face a casting issue when cloning it with the copy constructor.

To illustrate this issue, let’s first create a subclass of Employee and its copy constructor:

public class Manager extends Employee {
    private List<Employee> directReports;
    // ... other constructors

    public Manager(Manager manager) {
        super(manager.id, manager.name, manager.startDate);
        this.directReports = directReports.stream()
          .collect(Collectors.toList());
    }
}

Then, we declare an Employee variable and instantiate it with the Manager constructor:

Employee source = new Manager(1, "VietManager", startDate, directReports);

Since the reference type is Employee, we have to cast it to Manager type so that we can use the copy constructor of the Manager class:

Employee clone = new Manager((Manager) source);

We may get ClassCastException at runtime if the input object is not an instance of Manager class.

One way to avoid casting in the copy constructor is to create a new inheritable method for both classes:

public class Employee {
   public Employee copy() {
        return new Employee(this);
    }
}

public class Manager extends Employee {
    @Override
    public Employee copy() {
        return new Manager(this);
    }
}

In each class method, we call its copy constructor with the input of this object. In this way, we can guarantee that the generated object equals the caller object:

Employee clone = source.copy();

5. Conclusion

In this tutorial, we showed how to create a copy constructor with some code examples. Also, we discussed several reasons why we should avoid the clone method.

Copy constructor has a casting issue when we use it to clone a child class object whose reference type is the parent class. We provided one solution for this issue.

As always, the source code for the tutorial is available over on GitHub.

Related posts:

Java Program to Implement AttributeList API
Java Program to Check whether Undirected Graph is Connected using DFS
Jackson vs Gson
Rest Web service: Filter và Interceptor với Jersey 2.x (P2)
SOAP Web service: Authentication trong JAX-WS
Java Program to Check Whether an Input Binary Tree is the Sub Tree of the Binary Tree
Call Methods at Runtime Using Java Reflection
Java Program to Implement Dijkstra’s Algorithm using Set
Spring Boot - Unit Test Cases
Java Program to Describe the Representation of Graph using Incidence List
Java Program to Find the Shortest Path from Source Vertex to All Other Vertices in Linear Time
Java Program to Perform Deletion in a BST
Java – Try with Resources
Java Program to implement Array Deque
Java Program to Implement Extended Euclid Algorithm
Checking for Empty or Blank Strings in Java
Tạo chương trình Java đầu tiên sử dụng Eclipse
Implementing a Runnable vs Extending a Thread
Java Program to Check Whether a Given Point is in a Given Polygon
Jackson Annotation Examples
Spring Data Reactive Repositories with MongoDB
Java Program to Check whether Graph is Biconnected
Java Program to Implement Leftist Heap
Java Program to Perform Preorder Non-Recursive Traversal of a Given Binary Tree
Object Type Casting in Java
Spring MVC and the @ModelAttribute Annotation
Period and Duration in Java
Add Multiple Items to an Java ArrayList
Model, ModelMap, and ModelAndView in Spring MVC
Java Program to Implement Sorting of Less than 100 Numbers in O(n) Complexity
Java Program to Implement Double Order Traversal of a Binary Tree
Batch Processing with Spring Cloud Data Flow