In Java, Shallow Copy and Deep Copy refer to two different methods of copying an object and its associated data.
1. Shallow Copy
A shallow copy of an object copies the object’s fields, but does not copy objects referred to by reference fields. For reference types (like arrays or other objects), the reference is copied, but the actual object is not duplicated.
Only the top-level object is copied.
References to other objects are copied "as-is."
If the original object contains a reference to a mutable object, changes to the referenced object will affect both the original and copied objects.
Example:
class ShallowCopyExample implements Cloneable {
int number;
String text;
int[] array;
// Constructor
public ShallowCopyExample(int number, String text, int[] array) {
this.number = number;
this.text = text;
this.array = array;
}
// Shallow Copy using clone()
public Object clone() throws CloneNotSupportedException {
return super.clone(); // Performs shallow copy
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
int[] arr = {1, 2, 3};
ShallowCopyExample obj1 = new ShallowCopyExample(10, "Hello", arr);
ShallowCopyExample obj2 = (ShallowCopyExample) obj1.clone();
// Changing the array element in obj2
obj2.array[0] = 99;
System.out.println(obj1.array[0]); // Output will be 99, showing the array is shared
}
}
In this example, even though obj2 is a clone of obj1, changing the array in obj2 also affects obj1 because only the reference to the array was copied, not the array itself.
2. Deep Copy
A deep copy creates a completely independent copy of an object and all the objects it references. For every object referenced by the original object, a new copy is created recursively. Thus, changes to the copied object do not affect the original object.
Example:
class DeepCopyExample implements Cloneable {
int number;
String text;
int[] array;
// Constructor
public DeepCopyExample(int number, String text, int[] array) {
this.number = number;
this.text = text;
this.array = array;
}
// Deep Copy using clone()
public Object clone() throws CloneNotSupportedException {
// Perform shallow copy first
DeepCopyExample copied = (DeepCopyExample) super.clone();
// Manually create deep copy of mutable objects
copied.array = this.array.clone();
return copied;
}
}
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
int[] arr = {1, 2, 3};
DeepCopyExample obj1 = new DeepCopyExample(10, "Hello", arr);
DeepCopyExample obj2 = (DeepCopyExample) obj1.clone();
// Changing the array element in obj2
obj2.array[0] = 99;
System.out.println(obj1.array[0]); // Output will be 1, showing the array is NOT shared
}
}
Here, obj2's array is a completely new copy, so changing obj2 does not affect obj1.
What is the difference between shallow copy and deep copy in Java?
Follow-up: How does shallow copying affect object references?
Answer: Shallow copy only copies the top-level object. If there are references to other objects, they are shared between the original and the copy, meaning changes to one will affect the other.
When would you prefer to use shallow copy over deep copy?
Follow-up: What are the potential risks of using shallow copy?
Answer: Shallow copy is faster and useful when you don’t need to modify the referenced objects independently. However, the risk is that changes in the copy might inadvertently change the original object if references are shared.
How can you implement a deep copy in Java?
Follow-up: What are the ways to implement deep copy for complex objects?
Answer: Deep copy can be implemented by recursively cloning or manually copying each field, especially when fields are references to other objects. For mutable objects like arrays or collections, create new instances to avoid sharing.
Does Java provide built-in support for deep copying?
Follow-up: Why doesn’t the default clone() method perform a deep copy?
Answer: Java’s Object.clone() method only performs shallow copying. Deep copying isn't automatic because it's more resource-intensive and may not always be necessary. Implementing deep copy requires custom logic depending on the class’s structure.
How does serialization help in deep copying?
Follow-up: Can serialization be used for deep copy of any object? What are its limitations?
Answer: Serialization can be used for deep copying by serializing an object to a stream and then deserializing it. This creates a completely new instance. However, the class and its fields must implement Serializable, and it may have performance overhead due to the I/O operations.
// Example of deep copy using serialization
import java.io.*;
class DeepCopyUsingSerialization implements Serializable {
int number;
String text;
public DeepCopyUsingSerialization(int number, String text) {
this.number = number;
this.text = text;
}
public DeepCopyUsingSerialization deepCopy() throws IOException, ClassNotFoundException {
// Serialization
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// Deserialization
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (DeepCopyUsingSerialization) ois.readObject();
}
}
What are some scenarios where deep copying is necessary?
Follow-up: When might deep copying be inefficient or undesirable?
Answer: Deep copying is necessary when an object contains references to other objects and modifications to those referenced objects should not affect the original object. However, deep copying can be inefficient when dealing with large, complex object graphs, as it requires more memory and processing time.
Is the clone() method the only way to perform shallow or deep copying in Java?
Follow-up: What are other ways to implement object copying?
Answer: No, other ways include:
Copy constructors: A constructor that accepts an object and initializes a new one with its values.
Manual copying: Creating a new object and manually copying fields.
Serialization: As shown above, deep copying can be achieved by serializing and deserializing an object.
Can a shallow copy turn into a deep copy accidentally?
Follow-up: Can garbage collection affect shallow or deep copies?
Answer: No, a shallow copy cannot turn into a deep copy. Shallow copying copies references, so unless you explicitly copy objects recursively, it remains shallow. Garbage collection only affects objects that are no longer referenced and doesn’t directly affect the copying process.
How can collections (e.g., ArrayList) be shallow or deep copied?
Follow-up: What methods in Java collections can help in deep copying?
Answer: A shallow copy of a collection copies only the collection structure (e.g., ArrayList) but shares the elements. A deep copy requires copying both the collection structure and all elements inside it. For deep copying, you can iterate over the elements and copy each one (if they are mutable).
What is the impact of immutability on shallow and deep copying?
Follow-up: If all fields are immutable, is deep copy necessary?
Answer: If the fields in an object are immutable, shallow copy and deep copy become indistinguishable because immutable objects cannot be modified. In such cases, deep copying is not necessary since sharing immutable objects between copies is safe.