Deep Copy of Java ArrayList: Implementation and Principles

Dec 01, 2025 · Programming · 9 views · 7.8

Keywords: Java | ArrayList | Deep Copy

Abstract: This article provides an in-depth exploration of deep copy implementation for Java ArrayList, focusing on the distinction between shallow and deep copying. Using a Person class example, it details how to properly override the clone() method for object cloning and compares different copying strategies' impact on data consistency. The discussion also covers reference issues with mutable objects in collections, offering practical code examples and best practice recommendations.

Fundamental Concepts of ArrayList Copying

In Java programming, collection copying is a common requirement, yet many developers confuse shallow copy with deep copy. This distinction becomes particularly important when dealing with ArrayLists containing mutable objects. Shallow copy duplicates only the collection structure while keeping object references unchanged; deep copy replicates both the collection structure and all contained objects.

Problem Scenario Analysis

Consider this typical scenario: an ArrayList stores Person objects, each containing mutable attributes like name and date. After copying using the addAll() method, modifying object properties in the new list affects the original list because both lists share the same object references. This side effect is unacceptable in scenarios requiring data isolation.

Person morts = new Person("whateva");
List<Person> oldList = new ArrayList<Person>();
oldList.add(morts);
oldList.get(0).setName("Mortimer");

List<Person> newList = new ArrayList<Person>();
newList.addAll(oldList);

newList.get(0).setName("Rupert");

System.out.println("oldName : " + oldList.get(0).getName());
System.out.println("newName : " + newList.get(0).getName());

The output shows both lists' names changed to "Rupert", demonstrating the shallow copy issue.

Deep Copy Implementation Strategy

To achieve true deep copy, we must clone each element object while copying the collection. The core approach involves overriding the Person class's clone() method:

public class Person implements Cloneable {
    private String name;
    private Date birthDate;
    
    @Override
    public Person clone() {
        try {
            Person cloned = (Person) super.clone();
            // Deep copy mutable fields
            if (this.birthDate != null) {
                cloned.birthDate = (Date) this.birthDate.clone();
            }
            // String is immutable, no special handling needed
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

Then create a new list by iterating through the original list and cloning each element:

List<Person> newList = new ArrayList<>();
for (Person p : oldList) {
    newList.add(p.clone());
}

Implementation Details and Considerations

The key to deep copy lies in properly handling all mutable fields:

  1. Primitive types and immutable objects (e.g., String) can be copied directly
  2. Mutable objects require recursive calls to their clone() methods
  3. Array types need special handling using Arrays.copyOf() or loop copying
  4. Collection types require creating new collections and copying all elements

For Person classes containing complex types like BigDecimal or DateTime, ensure these types support cloning or provide alternative copying mechanisms.

Alternative Approaches Comparison

Beyond the cloning method, consider these alternatives:

Each approach has its applicable scenarios and performance considerations. The cloning method offers a good balance in most cases but requires awareness of the Cloneable interface's design limitations.

Performance and Memory Considerations

Deep copy creates complete duplicates of objects, therefore:

Best Practice Recommendations

  1. Clearly distinguish between shallow and deep copy usage scenarios
  2. Implement Cloneable interface and override clone() method for classes requiring copying
  3. Properly handle deep copy of all mutable fields in the clone() method
  4. Consider immutable object design to avoid copying needs
  5. Write unit tests to verify copying behavior correctness

By correctly implementing deep copy, we ensure data isolation in collection operations, prevent unexpected side effects, and improve code reliability and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.