Cloning in Java

Cloning in Java

Cloning in Java refers to the process of creating a copy of an object. Cloning can either be a shallow copy or a deep copy in java,. Cloning is useful when you need to duplicate an object while preserving its state.

In Java, Clone() method of Object class is used to clone the object. Class must implement the Cloneable interface to achieve clonable functionality. Means if you want to create a clone of an object of a particular class, that class should override clone() of the object class and a cloneable interface must be implemented by that class.

Cloneable Interface

The Cloneable interface is a marker interface in Java, which means it doesn’t declare any method. It is used to indicate that a class can be cloned.

 If we don’t implement Cloneable interface to a class, and try to clone the object of that class , clone() method throws CloneNotSupportedException.

clone() Method

Syntaxprotected Object clone() throws CloneNotSupportedException  

The clone() method is a protected method defined in the Object class, and it’s responsible for creating a copy of an object.In clone() , you can write code to provide custom behavior while cloning your class object.

It returns an Object reference, that you need to typecast to the appropriate type. Like If you are cloning Student Object, then Cloned Object should be type cast Student.

Student s1=new Student("RoundTheTech", 12, "A");  
		  
Student s2=(Student)s1.clone();

To use the clone() method effectively, you should override it in your class to provide a proper implementation.

Although you can override clone() without implementing Cloneable interface but once you try to clone the object of class which is not implementing Cloneable interface it will throw CloneNotSupportedException

How Clone Method Works

When you call the clone() method on an object, it creates a new instance of the same class and initializes its fields with the same values as the original object. Depending on the implementation, this can result in either a shallow copy or a deep copy.

A clone object follows basic characteristics e.g. 

  1. a.clone() != a, which means original and clone are two separate object in Java heap
  2. a.clone().getClass() == a.getClass() means  original and clone presenting to same class
  3. clone.equals(a), which means clone is exactly a copy of the original object. 

clone() Method Example

1. Example to clone() with implementing Cloneable interface: We have a School class and we want to make a clone object of this class. To achieve it, as per rule, school class implements Cloneable interface and overrides clone() method. When we create the clone of this class, We get a message on console Cloning is done successfully.

package com.clone.learn;

public class School implements Cloneable{
	private String schoolName;
	private String address;
	
	public School() {
		
	}
	public School(String name, String address) {
		this.schoolName = name;
		this.address = address;
	}
	
	public String getSchoolName() {
		return schoolName;
	}
	public void setSchoolName(String schoolName) {
		this.schoolName = schoolName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	@Override
	public String toString() {
		return "School [schoolName=" + schoolName + ", address=" + address + "]";
	}
		
	
	public static void main(String[] args) {
		try {
		School s1 = new School("ABC", "India");  
		  
		School s2 = (School)s1.clone();
		
		System.out.println("Cloning is done successfully.");
		} catch (CloneNotSupportedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}



OutPut on Console:
 Cloning is done successfully.

2. Example to clone() without implementing Cloneable interface: In this Example, We are overriding clone() method but not implementing Cloneable interface. We will not get any compilation error but once we run this code to clone the object, Runtime CloneNotSupportedException will be produced.

package com.clone.learn;

public class School {
	private String schoolName;
	private String address;
	
	public School() {
		
	}
	public School(String name, String address) {
		this.schoolName = name;
		this.address = address;
	}
	
	public String getSchoolName() {
		return schoolName;
	}
	public void setSchoolName(String schoolName) {
		this.schoolName = schoolName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	@Override
	public String toString() {
		return "School [schoolName=" + schoolName + ", address=" + address + "]";
	}
		
	
	public static void main(String[] args) {
		try {
		School s1 = new School("ABC", "India");  
		  
		School s2 = (School)s1.clone();
		
		System.out.println("Cloning is done successfully.");
		} catch (CloneNotSupportedException e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}


Output on Console: 

java.lang.CloneNotSupportedException: com.clone.learn.School
	at java.lang.Object.clone(Native Method)
	at com.clone.learn.School.clone(School.java:29)
	at com.clone.learn.School.main(School.java:42)

Types of Cloning in Java

There are 2 types of cloning,

  1. Shallow cloning 
  2. Deep Cloning

1. Shallow Copy (Cloning) of an Object

By default the clone method creates a shallow copy of the source object.

Shallow cloning in Java creates a new object, but the reference fields of the cloned object and original object share the same object. 

Means whenever we create a shallow copy of an object, all fields of the original objects are copied exactly. But, if it contains any objects of a class as fields then, only references to those objects are copied, not the complete objects. That is why when you change a cloned object it reflects the original object and vice versa.

Example:

To illustrate this concept, let’s consider an example involving a class(Student) that contains a reference to another object (School).  Shallow cloning of a Student  creates a new Student object referencing the same School object as the original Student. If any changes made to the School object of the cloned Student  object, It reflects to the original Student’ school object and vice versa. Both Original and Cloned objects share the same memory for reference objects.

  • In  main method we creates Student object like this 

School school =new School(“ABC”, “India” );

Student student1 = new Student(“RoundTheTech”,12,”A”, school);

Where 

Student name =“RoundTheTech” , Age=12, School Name = “ABC” and school address =”India”

  • From this Student1 object we create a new cloned object student2. 
  • If we print values of student1 and student2, object values on the console are same.
  • When we make changes in cloned student2 object for studentname, age and school address and print on console
    1. Student name and age values are not same for original and cloned object because both are not reference objects.
    2. But School Address is same  for original and cloned object because school is a reference object.

Java Code:

For Shallow cloning,  school object cloning is also done with student object cloning in clone() of Student.

School.java

package com.clone.learn;

public class School implements Cloneable{
	private String schoolName;
	private String address;
	
	public School() {
		
	}
	public School(String name, String address) {
		this.schoolName = name;
		this.address = address;
	}
	
	public String getSchoolName() {
		return schoolName;
	}
	public void setSchoolName(String schoolName) {
		this.schoolName = schoolName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	@Override
	public String toString() {
		return "School [schoolName=" + schoolName + ", address=" + address + "]";
	}
			
}

Student.java

package com.clone.learn;

public class Student implements Cloneable{
  	private String name;
	private int age;
	private String grade;
	private School school;
 
   	public Student() {
        
   	}

	public Student(String name, int age, String grade, School school) {
		super();
		this.name = name;
		this.age = age;
		this.grade = grade;
		this.school = school;
	}

		
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getGrade() {
		return grade;
	}

	public void setGrade(String grade) {
		this.grade = grade;
	}

	public School getSchool() {
		return school;
	}

	public void setSchool(School school) {
		this.school = school;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", grade=" + grade + ", school=" + school + "]";
	}

	public static void main(String[] args) {
		
		try  {
			School school =new School("ABC", "India" );
			Student student1 = new Student("RoundTheTech",12,"A", school);
			Student student2 = (Student) student1.clone();
			
			//After cloning 
			System.out.println("Student1.getName() :::[" + student1.getName() 
			+ "], School Name:::[" + student1.getSchool().getSchoolName()
			+ "], age : [" + student1.getAge()+"]");
			
			
			System.out.println("Student2.getName() :::[" + student2.getName() 
			+ "], School Name:::[" + student2.getSchool().getSchoolName()
			+ "], age : [" + student2.getAge()+"]");
			
			System.out.println("\n After changing values in cloned object************");
			//Changing student name, Age and School Name
			student2.setName("Gauri");
			student2.setAge(20);
			student2.getSchool().setSchoolName("ABC_New");
				
			System.out.println("Student1.getName() :::[" + student1.getName() 
			+ "], School Name:::[" + student1.getSchool().getSchoolName()
			+ "], age : [" + student1.getAge()+"]");
			
			
			System.out.println("Student2.getName() :::[" + student2.getName() 
			+ "], School Name:::[" + student2.getSchool().getSchoolName()
			+ "], age : [" + student2.getAge()+"]");
			
		} catch (Exception e) {
			
		}
		
	}
   	
}

Output : 

Student1.getName() :::[RoundTheTech], School Name:::[ABC], age : [12]

Student2.getName() :::[RoundTheTech], School Name:::[ABC], age : [12]

 After changing values in cloned object************

Student1.getName() :::[RoundTheTech], School Name:::[ABC_New], age : [12]

Student2.getName() :::[Gauri], School Name:::[ABC_New], age : [20]

2. Deep Copy (Cloning)

A deep copy of an object creates a new object and recursively copies all reference type objects by the original object. This ensures that changes made to the cloned object or its fields do not affect to the original object.

It means in Java, during the cloning process, an exact copy of all the fields of the original object is created in the cloned object.If the original object has references to other objects as fields then a copy of those objects will also be created. By Deep cloning, a cloned object  is independent of the original object and any changes made in the cloned object won’t be reflected to original object and vice versa.

Example:

To understand the Deep Copy concept, let’s consider an example . Suppose we have a Student class and a School class, where a School has an associated School . Deep cloning of a Student, creates a new Student object  with new School object. If Any changes are made in Original student’s school object it will not reflect to the cloned’s school object and vice versa. Both Original and cloned objects will work as separate objects even for reference objects too.

  • We have a Student class which has a School object. In main method we creates Student object like this 

School school =new School(“ABC”, “India” );

Student student1 = new Student(“RoundTheTech”,12,”A”, school);

Where 

Student name =“RoundTheTech” , Age=12, School Name = “ABC” and school address =”India”

  • From this Student1 object we create a new cloned object student2. 
  • If we print values of student1 and student2 object value on console, both are same.
  • When we make changes in clone 2 object for studentname, age and school address and print on console, All values are different both original and cloned objects.

Java Code:

For deep cloning,  school object cloning is also done with student object cloning in clone() of Student.

School.java

package com.clone.learn;

public class School implements Cloneable{
	private String schoolName;
	private String address;
	
	public School() {
		
	}
	public School(String name, String address) {
		this.schoolName = name;
		this.address = address;
	}
	
	public String getSchoolName() {
		return schoolName;
	}
	public void setSchoolName(String schoolName) {
		this.schoolName = schoolName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
	@Override
	public String toString() {
		return "School [schoolName=" + schoolName + ", address=" + address + "]";
	}
			
}

Student.java

package com.clone.learn;

public class Student implements Cloneable{
  	private String name;
	private int age;
	private String grade;
	private School school;
 
   	public Student() {
        
   	}

	public Student(String name, int age, String grade, School school) {
		super();
		this.name = name;
		this.age = age;
		this.grade = grade;
		this.school = school;
	}

		
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getGrade() {
		return grade;
	}

	public void setGrade(String grade) {
		this.grade = grade;
	}

	public School getSchool() {
		return school;
	}

	public void setSchool(School school) {
		this.school = school;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Student student = (Student) super.clone();
		student.school = (School) school.clone();
		return student;
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", grade=" + grade + ", school=" + school + "]";
	}

	public static void main(String[] args) {
		
		try  {
			School school =new School("ABC", "India" );
			Student student1 = new Student("RoundTheTech",12,"A", school);
			Student student2 = (Student) student1.clone();
			
			//After cloning 
			System.out.println("Student1.getName() :::[" + student1.getName() 
			+ "], School Name:::[" + student1.getSchool().getSchoolName()
			+ "], age : [" + student1.getAge()+"]");
			
			
			System.out.println("Student2.getName() :::[" + student2.getName() 
			+ "], School Name:::[" + student2.getSchool().getSchoolName()
			+ "], age : [" + student2.getAge()+"]");
			
			System.out.println("\n After chaning values in cloned object************");
			//Changing student name, Age and School Name
			student2.setName("Gauri");
			student2.setAge(20);
			student2.getSchool().setSchoolName("ABC_New");
				
			System.out.println("Student1.getName() :::[" + student1.getName() 
			+ "], School Name:::[" + student1.getSchool().getSchoolName()
			+ "], age : [" + student1.getAge()+"]");
			
			
			System.out.println("Student2.getName() :::[" + student2.getName() 
			+ "], School Name:::[" + student2.getSchool().getSchoolName()
			+ "], age : [" + student2.getAge()+"]");
			
		} catch (Exception e) {
			
		}
		
	}
   	
}




Output:
Student1.getName() :::[RoundTheTech], School Name:::[ABC], age : [12]
Student2.getName() :::[RoundTheTech], School Name:::[ABC], age : [12]


 After chaning values in cloned object************
Student1.getName() :::[RoundTheTech], School Name:::[ABC], age : [12]
Student2.getName() :::[Gauri], School Name:::[ABC_New], age : [20]

Advantage and Disadvantage of Object Cloning

Advantage of Object cloning

  • Cloning is more efficient than manually copying every field of an object. 
  •  Cloning allows you to duplicate an object and its state. Like backups or parallel processing without altering the original data.
  • Change in reference object by one object will reflect to all objects.

Disadvantage of Object cloning

  • Implementing a proper clone() method can be challenging, especially for complex classes with nested objects. Ensuring a deep copy when needed can add complexity to your code.
  • Improperly implemented cloning can lead to security vulnerabilities, as malicious code might exploit the clone to access or modify sensitive data.

Java Cloning Key Points

  • To create copy of an object, cloning is done by implementing the java.lang.Cloneable interface and override protected clone() method from java.lang.Object.
  • IF Cloneable interface not implemented, a call of clone() method will result in CloneNotSupportedException.
  • Constructor is not called during cloning in java.
  • Default implementation of clone() method provides shallow cloning in java.
  • If a class contains a reference field both original object and cloned object will refer to the same object.
  • By convention, clone of an instance should be obtained by calling super.clone() method, this will help to preserve invariant of object created by clone() method.

Difference Between Deep vs Shallow Cloning

AspectDeep CloningShallow Cloning
New Object CreationCreates a new object for all fields including reference fields by the original object’s fields.Creates a new object for all fields but for reference fields it shares the same objects as the original object.
IndependenceThe cloned object and Original objects are entirely independent. Changes in one do not affect to the other.The cloned object shares references with the original object. Changes in one may affect to the other.
ComplexityTypically more complex to implement, especially when dealing with complex object graphs and nested structures.Simpler to implement as it follows default implementation. It often involves a basic field assignment.
Use CasesWhen you want to create a deep copy of an object and its internal state, ensuring that changes in the clone don’t affect the original.When you want to create a copy of an object but are fine with some shared references to internal objects, possibly for performance reasons.
Default BehaviorNot provided by default; you need to implement deep cloning logic yourself, potentially recursively.Provided by default via the clone() method in Java.
Object Graph TraversalRequires traversing the entire object graph and copying each nested object, potentially leading to more memory usage and time complexity.Only copies the top-level fields, resulting in lower memory usage and potentially faster cloning.

Conclusion

Cloning in Java allows you to create copies of objects, and the Cloneable interface and clone() method are the key components of this process. Deep cloning creates completely independent copies of objects and their internal objects, while shallow cloning results in copies that share references to some or all of the internal objects. The choice between deep and shallow cloning depends on your specific requirements and the structure of your object hierarchy.

P.S. We welcome your feedback. Please comment, if you find anything incorrect, or want to share more information about the topic or want to share any kind of feedback.

Leave a Reply

Your email address will not be published. Required fields are marked *