Shallow Copy

May 20, 2023

A shallow copy is a type of object copy in which a new object is created with the same values as an existing object, but with references to the same objects for any reference type fields. In other words, a shallow copy creates a new object that has the same values as the original object, but it does not create new copies of the objects referenced by the original object. Instead, it refers to the same objects as the original.

Purpose

The purpose of creating shallow copies is to reduce the amount of memory required to store objects. When objects are copied, their values need to be stored in memory, and any reference type fields must also be copied. This can be very time-consuming and memory-intensive, especially for large objects with many fields. By creating a shallow copy instead, only the values of the object are stored in memory, while the reference type fields are simply pointed to the same objects as the original, reducing the amount of memory required.

Usage

Shallow copies are commonly used in programming languages that support object-oriented programming, such as Java, Python, and C#. In Java, for example, the clone() method can be used to create a shallow copy of an object. The Object.clone() method creates a new object that is a copy of the original object, but with references to the same objects as the original.

public class MyClass implements Cloneable {
    public int value;
    public MyObject obj;

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

In this example, the MyClass object has a field obj of type MyObject. When a shallow copy of MyClass is created, the new object will have a reference to the same MyObject as the original.

MyClass obj1 = new MyClass();
obj1.value = 10;
obj1.obj = new MyObject();

MyClass obj2 = (MyClass) obj1.clone();
obj2.value = 20;
obj2.obj.setValue(30);

System.out.println(obj1.value); // Output: 10
System.out.println(obj2.value); // Output: 20

System.out.println(obj1.obj.getValue()); // Output: 30
System.out.println(obj2.obj.getValue()); // Output: 30

In this example, obj1 is an instance of MyClass with a value of 10 and a MyObject field with a value of 0. obj2 is a shallow copy of obj1, so it has the same value of 10 and references the same MyObject. When the value of obj2.value is changed to 20, it does not affect the value of obj1.value because they are separate objects. However, when the value of obj2.obj is changed to 30, it affects the value of obj1.obj as well because they reference the same object.

Shallow copies can also be used to create copies of collections, such as arrays and lists, that contain reference types. In Java, for example, the Arrays.copyOf() method can be used to create a shallow copy of an array. This method creates a new array with the same length as the original and copies the values of the original array into the new array. However, any reference type elements in the array are simply pointed to the same objects as the original array.

MyObject[] array1 = new MyObject[3];
array1[0] = new MyObject();
array1[1] = new MyObject();
array1[2] = new MyObject();

MyObject[] array2 = Arrays.copyOf(array1, array1.length);

array2[0].setValue(10);

System.out.println(array1[0].getValue()); // Output: 10
System.out.println(array2[0].getValue()); // Output: 10

In this example, array1 is an array of MyObject with a length of 3, and array2 is a shallow copy of array1. When the value of array2[0] is changed to 10, it affects the value of array1[0] as well because they reference the same MyObject.

Comparison with Deep Copy

A shallow copy is often compared with a deep copy, which creates a new object with new copies of all the objects referenced by the original object. In other words, a deep copy creates a new object that is completely independent of the original object, whereas a shallow copy creates a new object that shares some objects with the original object.

public class MyClass implements Cloneable {
    public int value;
    public MyObject obj;

    public Object clone() {
        try {
            MyClass copy = (MyClass) super.clone();
            copy.obj = (MyObject) obj.clone();
            return copy;
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

In this example, the clone() method creates a shallow copy of the MyClass object using the super.clone() method, and then creates a deep copy of the MyObject field using the obj.clone() method. This creates a new MyObject object that is independent of the original MyObject.

MyClass obj1 = new MyClass();
obj1.value = 10;
obj1.obj = new MyObject();

MyClass obj2 = (MyClass) obj1.clone();
obj2.value = 20;
obj2.obj.setValue(30);

System.out.println(obj1.value); // Output: 10
System.out.println(obj2.value); // Output: 20

System.out.println(obj1.obj.getValue()); // Output: 0
System.out.println(obj2.obj.getValue()); // Output: 30

In this example, obj1 is an instance of MyClass with a value of 10 and a MyObject field with a value of 0. obj2 is a deep copy of obj1, so it has a new MyObject with a value of 0. When the value of obj2.value is changed to 20, it does not affect the value of obj1.value because they are separate objects. When the value of obj2.obj is changed to 30, it does not affect the value of obj1.obj because they reference different objects.