Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Default Copy Constructor in Java

DZone's Guide to

Default Copy Constructor in Java

Amit Kumar Mondal provides insight into the Copy constructor within Java and the perils in Shallow Copy.

· Java Zone
Free Resource

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

In the good old days of our programming, we all have learnt about C++. If you remember, in C++, we used to have Copy Constructor to copy an object. But in Java, how do we copy an object? We all are aware of the clone method inside Object class which is used to clone an object. But we still do have some fallacies in it.

Default Copy Constructor

Let’s consider we have an entity called Student which holds another entity called Result.

Result POJO

public final class Result {

private final int marks;

public Result(final int marks) {
this.marks = marks;
}

public int getMarks() {
return this.marks;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this.getClass()).add("marks", this.marks).toString();
}

}

Student POJO

public final class Student {

private final String name;

private final Result result;

public Student(final String name, final Result result) {
checkNotNull(name);
checkNotNull(result);

this.name = name;
this.result = result;
}

public String getName() {
return this.name;
}

public Result getResult() {
return this.result;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this.getClass()).add("name", this.name).add("result", this.result).toString();
}

}

So, each and every object of Student will hold a pointer to the actual Result object.

Application Client

public final class DefalutCopyConstructor {

public static void main(final String[] args) {
final Result result = new Result(50);
final Student student = new Student("Sam", result);
System.out.println(student);
}

}

If you run the previous code, you can get a Student object which holds a reference to the Result object. Now, if I want to create another object, I can create it the same way I did in the previous example.

public final class DefalutCopyConstructor {

public static void main(final String[] args) {
final Result result1 = new Result(50);
final Student student1 = new Student("Sam", result1);

final Result result2 = new Result(50);
final Student student2 = new Student("Dean", result2);

System.out.println(student1);
System.out.println(student2);
}

}

Now, we have another student object created. If you check using the equality operator, it would report false as both the references (student1 and student2) are pointing to different objects in the heap.

If we want to copy the object of student1 to a reference of student2, I would try to write a syntax like the following one.

public final class DefalutCopyConstructor {

public static void main(final String[] args) {
final Result result1 = new Result(50);
final Student student1 = new Student("Sam", result1);

final Student student2 = new Student(student1);

System.out.println(student1);
System.out.println(student2);
}

}

This clearly will report a compilation error.

The constructor Student(Student) is undefined

But think, Java could have given us a Default Copy Constructor like this but it didn’t.

Why? Because of the perils in Shallow Copy

Shallow Copy

If you write the same program in C++ and try to use the default constructor to copy the object of student1 to student2, it would copy the complete object of student1. But it won’t copy the actual object of result which the object of student1 holds. It will only have a pointer to the previous object (result).

student1 ——————> result <——————- student2

Here, student1 refers to a Student object which contains a Result object reference. Now, student2 will refer to a completely new Student object but this new Student object will still contain the Result reference to the old Result object. So, you can clearly see that the objects are not deeply copied but the references.

Due to this peril in copying object, Java didn’t provide the Default Copy Constructor.

Solution (Deep Copy)

We could then try to implement our own copy constructor to copy the objects deeply. Let’s try to implement it.

Result POJO with Copy Constructor

public final class Result {

private final int marks;

public Result(final int marks) {
this.marks = marks;
}

public Result(final Result result) {
this.marks = result.getMarks();
}

public int getMarks() {
return this.marks;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this.getClass()).add("marks", this.marks).toString();
}

}

Student POJO with Copy Constructor

public final class Student {

private final String name;

private final Result result;

public Student(final String name, final Result result) {
checkNotNull(name);
checkNotNull(result);

this.name = name;
this.result = result;
}

public Student(final Student student) {
this.name = student.getName();
this.result = new Result(student.getResult());
}

public String getName() {
return this.name;
}

public Result getResult() {
return this.result;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this.getClass()).add("name", this.name).add("result", this.result).toString();
}

}

Client Application

public final class DefalutCopyConstructor {

public static void main(final String[] args) {
final Result result1 = new Result(50);
final Student student1 = new Student("Sam", result1);

final Student student2 = new Student(student1);

System.out.println(student1);
System.out.println(student2);
}

}

Benefit

Due to this implementation, we have completely got rid of the Shallow Copy problem. It means now, we can make exact copies of each and every object whether it is Student object or a Result object. The copy of the Student object will no longer refer to the Result object contained by any other Student object. Instead, it will contain a new Result object reference.

Problem

But the problem lies in maintainability.

Let’s say we have a requirement to add another new property to the Result class, namely Grade. This procedure of adding Copy Constructor to each and every class has to be done.

Let’s consider another example. If we have several different kinds of Result types then in Student copy constructor we have to have an instance of type check on each and every type of Result instance which eventually makes the code less readable, error-prone and not extensible.

This violates Open-Closed Principle.

Solution

You might be thinking that clone method from Object class could be our key to the rescue but it also incurs the similar problem. Just to keep it simple and silly, I am going to discuss the clone method in my upcoming post.

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
java ,c++ ,java development

Published at DZone with permission of Amit Kumar Mondal, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}