Answer
Deep Copy vs Shallow Copy
The Difference
- ✓Shallow Copy — copies the object but keeps references to the same nested objects
- ✓Deep Copy — copies the object AND all nested objects recursively (fully independent)
CODE
Original: Address ──┐
Employee ───────────── ┘ ← same object
Shallow: Address ──┐
Employee2 ─────────── ┘ ← still pointing to same Address!
Deep: Address (ORIGINAL)
Employee ───────────────────
Employee2 ─── Address (NEW COPY) ← fully independent
Classes Used in Examples
Java
public class Address {
String city;
String country;
Address(String city, String country) {
this.city = city;
this.country = country;
}
}
public class Employee {
String name;
Address address; // nested object
Employee(String name, Address address) {
this.name = name;
this.address = address;
}
}
Shallow Copy
Java
// Method 1: new object + copy primitives/references
Employee original = new Employee("Alice", new Address("New York", "USA"));
Employee shallowCopy = new Employee(original.name, original.address); // same Address ref!
// Modify the copy's nested object
shallowCopy.address.city = "London";
// Original is ALSO changed — same Address object!
System.out.println(original.address.city); // "London" ← CHANGED!
System.out.println(shallowCopy.address.city); // "London"
Shallow Copy with clone() (implements Cloneable)
Java
public class Employee implements Cloneable {
String name;
Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // shallow clone — copies reference to address
}
}
Employee copy = (Employee) original.clone();
// copy.address still points to same Address as original
Deep Copy — Manual
Java
public class Employee implements Cloneable {
String name;
Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
Employee deepCopy = (Employee) super.clone();
// Manually clone the nested object
deepCopy.address = new Address(this.address.city, this.address.country);
return deepCopy;
}
}
Employee original = new Employee("Alice", new Address("New York", "USA"));
Employee deepCopy = (Employee) original.clone();
deepCopy.address.city = "London";
System.out.println(original.address.city); // "New York" ← NOT changed!
System.out.println(deepCopy.address.city); // "London"
Deep Copy via Serialization (Easy for complex graphs)
Java
// Both classes must implement Serializable
public static <T extends Serializable> T deepCopy(T obj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("Deep copy failed", e);
}
}
Employee deepCopy = deepCopy(original); // fully independent copy
Deep Copy via Copy Constructor (Recommended)
Java
public class Employee {
String name;
Address address;
// Copy constructor — deep copy
public Employee(Employee other) {
this.name = other.name;
this.address = new Address(other.address.city, other.address.country);
}
}
Employee copy = new Employee(original); // clean, explicit deep copy
In Automation Testing
Java
// Deep copy test data to avoid mutations between tests
TestData original = new TestData("Alice", new Config("chrome", "https://qa.example.com"));
TestData testCopy = original.deepCopy(); // each test gets independent copy
// Modifying testCopy doesn''t affect original
testCopy.config.url = "https://staging.example.com";
// original.config.url still = "https://qa.example.com"
