Create Copy of Object by Copy Constructor, Static Factory in Java
In the previous post, we discussed on creating the copy of object by clone() method. But one of main shortcome in the clone method is assigning value to final variables. Final variables can be assigned in declaration or in constructors. So your class has final members and copy of object required, it can’t be achieved by clone() method. The fix that shortcoming, we have to use copy constructor instead of clone() method. All the copy of object rule for clone is applicable for copy constructor and static factory both. Implementation rules are
1) Copy of object and actual object should not refer at same object. If it is same, that is not copy of object and that would be two references to a same object. So it should satisfy the rule, Copy of object != object.
2) Class of copy object and actual object should be same. The rule is, Class of Copy of Object == Class of Object.
3) Copy of object and actual object should be logically. The rule is, Copy of object.equals(object).
Copy Constructor :
Copy Constructor is special constructor for creating new object as a copy of an existing object. It defines the actions performed while copying class objects. It is highly recommeanded to have copy constructor in all the classes. Copy constructor implementation as below,
- It should have only one argument.
- It accepts only parameter that is another instance of the same class.
- Copy constructor should copy the primitive by assignment operation.
- Reference type variables should be created by new operator or by clone method(if clone is available).
- It should return deep copy of the object.
- Copy constructor does not require to implement any special interface. Clone() method requires cloneable interface.
Below the implementation of copy constructor of parent class Employee and child class ContractEmployee. Employee parent class and ContractEmployee is a child class.
package info.javaarch;
class Employee{
private final String name;
private String identifier;
public Address address;
// Getter, setter and default constructor for Employee
public Employee(Employee e) { //Copy constructor for Employee.
this.name = e.name;
this.identifier = e.identifier;
this.address = new Address(e.address);
}
}
class ContractEmployee extends Employee{
int dailyWages;
// Getter, setter and default constructor for ContractEmployee
public ContractEmployee(ContractEmployee emp ) { // Copy constructor for ContractEmployee
super(((Employee)emp));
this.dailyWages = emp.dailyWages;
}
}
Address address = new Address(“Street No1”, “NJ”);
ContractEmployee employee1 = new ContractEmployee(“John”, “0001”,address,100);
ContractEmployee employee2 = new ContractEmployee(employee1);
System.out.println(employee1 == employee2); // Return false ; Satisfies Rule1
System.out.println(employee1.getClass().equals(employee2.getClass())); // Returns true ; Satisfies Rule 2
System.out.println(employee1.equals(employee2)); // Returns true ; Satisfies Rule 3.
This implementation is fine to copy the final variables in the class. Now final variable issue resolved by copy constructor. Copy Constructor can handle,
1). final variable can be assigned in constructor.
2). Does not require any interface to be implemented
3). Each new instance creation invokes one constructor by default. Clone() method does not invoke constructor.
Now we discussed advantage over clone() method in copy constructor. Now one more implementation to copy the object, static factory. Why static factory is require to copy the object over clone() and copy construtor? Think for 2 min and validate your answer in next 10 min.
Static Factory to create copy of the object:
We discussed copy constructor and created copy of ContractEmployee object. But java allows parent class object can refer child class reference. Let us change the above code to find the issue in copy constructor.
Address address = new Address(“Street No1”, “NJ”);
Employee employee1 = new ContractEmployee(“John”, “0001”,address,100); // Employee object refers ContractEmployee
ContractEmployee employee2 = new ContractEmployee(employee1); // Compilation error as ContractEmployee(Employee) implementation is not exist
Employee employee3 = new Employee(employee1); // Would compile, but copy only parent class variables and child class variable would not be copied.
Copy constructor would not work as expected if we try to access the child class by parent reference. It is kind of restricting the use of inheritance and polymorphism of OOPS principles. To overcome this issue, implement copy constructor by static factory. Static factory implementation internally invoke copy constructor. But it is being called based on actual reference of the object and not by type of object. So it would resolve the issue in inheritance related to copying the object.
package info.javaarch;
class Employee {
private final String name;
private String identifier;
public Address address;
public Employee(Employee e) {
this.name = e.name;
this.identifier = e.identifier;
this.address = new Address(e.address);
}
public Employee newInstance() { // static factory implementation
return new Employee(this); // static factory invokes copy constructor
}
}
class ContractEmployee extends Employee{
int dailyWages;
public ContractEmployee(ContractEmployee emp ) {
super(((Employee)emp));
this.dailyWages = emp.dailyWages;
}
public ContractEmployee newInstance() { // Static factory implementation
return new ContractEmployee(this); // static factory invokes copy constructor
}
}
class Address {
// Implementation of Address
}
public class CopyOfObjects {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address(“Street No1”, “NJ”);
Employee employee1 = new ContractEmployee(“John”, “0001”,address,100); //Parent refernce refer child object
ContractEmployee employee2 = (ContractEmployee) employee1.newInstance(); //copy of ContractEmployee
ContractEmployee employee = new ContractEmployee(“Jack”, “0002”,address,100); //child reference refer child object
ContractEmployee copyOfEmp = employee.newInstance(); //copy of ContractEmployee
System.out.println(employee1 == employee2); // Return false ; Satisfies Rule1
System.out.println(employee1.getClass().equals(employee2.getClass())); // Returns true ; Satisfies Rule 2
System.out.println(employee1.equals(employee2)); // Returns true ; Satisfies Rule 3.
}
}
Static factory implementation overcome the issue of copying object by copy constructor in parent-child relationship. Use static factory implementation if final variable is in class and proper implementation static factory in parent-child relationship.
We have discussed on intention to create copy of an object, clone() method implementation, copy constructor & static factory implementation, shallow copy vs deep copy of object. Creating copy of object from existing copy is defined as prototype design pattern in java. We discuss prototype more on java design pattern. Kindly share your comments on creating copy of objects.