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:

Introduction to Spring Cloud CLI
Guide To CompletableFuture
Rest Web service: Filter và Interceptor với Jersey 2.x (P2)
Hướng dẫn sử dụng Java Generics
Java Program to Implement Aho-Corasick Algorithm for String Matching
Hướng dẫn Java Design Pattern – Singleton
Introduction to PCollections
How to Get the Last Element of a Stream in Java?
Quick Guide to Spring MVC with Velocity
Java Program to Implement PriorityBlockingQueue API
Java Program to Convert a Decimal Number to Binary Number using Stacks
ETL with Spring Cloud Data Flow
Java Program to Perform Search in a BST
REST Web service: Tạo ứng dụng Java RESTful Client với Jersey Client 2.x
Spring Boot - Building RESTful Web Services
Java Program to Emulate N Dice Roller
Wrapper Classes in Java
Hướng dẫn sử dụng luồng vào ra nhị phân trong Java
Java Program to Print the Kind of Rotation the AVL Tree is Undergoing
Automatic Property Expansion with Spring Boot
Java Program to Implement the Bin Packing Algorithm
Hướng dẫn Java Design Pattern – Flyweight
Giới thiệu Aspect Oriented Programming (AOP)
Finding the Differences Between Two Lists in Java
Java Program to Implement the Vigenere Cypher
Redirect to Different Pages after Login with Spring Security
Java Program to Implement Self Balancing Binary Search Tree
Transactions with Spring and JPA
Java Program to Generate All Possible Subsets with Exactly k Elements in Each Subset
Intro to the Jackson ObjectMapper
Java Program to Implement Leftist Heap
Spring 5 and Servlet 4 – The PushBuilder