Java Array Cloning, Shallow and Deep Copy

Java Array Cloning, Shallow and Deep Copy

Cloning, shallow copy and deep copy in Java are the ways of copying the attributes of one object into another of same type. Cloning, and shallow copy in Java are the same things. Java provides a clone method that copies the attributes of one object into another using shallow copy. Cloning Arrays in Java and other objects sometimes behave differently. Java Language Specification states that a clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.

Why is Java's Clone Needed?

To understand the need of Java's clone() method we first have to understand what is the difference between a reference to an object in memory and an altogether separate copy of an object. When more than one reference points to a single object in memory and the state of the object is changed by using any reference, all references retain the same behaviour because underneath the object in memory is the same for all references. This does not happen when there are separate copies. We need to clone a Java object when it is a parameter or return value of one of the public methods. If the object is a method parameter, then we don't want the caller to modify it later. Likewise, if we return an object that is part of our class's internal state, we should return a copy instead of a reference so that callers can't accidentally or deliberately change that internal state.

Java Arrays: Cloning and Shallow Copy

Cloning or shallow copy and deep copy in Java have purpose when it comes to objects; primitive types are always copied by their value. Arrays in Java are objects; therefore they inherit all the characteristics of java.lang.Object. An array type has a public method clone(), which overrides the clone() method of class Object. An array type inherits all methods except clone from Object class. The clone method of an array type returns a duplicate copy of the same array. Also note that every Java array implements the interfaces Cloneable and java.io.Serializable. Following program acquaints you to cloning of arrays in Java.

/* ArrayCloneDemo.java */
// Demonstrating cloning of array objects
public class ArrayCloneDemo
{
    public static void main(String[] args)
    {
        int ai[] = {1, 2, 3, 4, 5};
 
        /* copying the reference ai to aic,
         * after following assignment, aic
         * will point to the same array ai points.
         */
        int aic[] = ai; 
 
        aic[2] = -9;
 
        /* both print statements will print
         * the same result because ai, and aic
         * are the reference of same array, then no matter
         * which reference is being used to update array values.
         */
        System.out.println(aic[2]);
        System.out.println(ai[2]);
 
        /* Now illustrating clone(). 
         * In below assignment ai.clone() creates
         * a separate copy of the array in memory
         * and then assigns it to aic. Now, both 
         * ai and aic point to two different arrays
         * so changes made to one will not impact the other
         */
        System.out.println("---"); //separator
        aic = ai.clone();
        aic[1] = -15;
 
        /* both print statements will print 
         * the value stored at 1st index in the array
         * they point to.
         */
        System.out.println(aic[1]);
        System.out.println(ai[1]);
    }
}
 
OUTPUT
======
-9
-9
---
-15
2

In above example we see cloning of one dimensional array, where aic has a cloned array or a separate copy of ai after executing aic = ai.clone(); statement.

Cloning could be a feasible solution in case of one dimensional arrays of basic types or objects that have only primitive types as their members. But, it does not guarantee to work as you expect if the array contains objects of type Object or Cloneable or java.io.Serializable or other user defined types those further can contain sub-objets, or the array has more than one dimension. Cloning can fail in case of objects that have other objects as their members. You may be thinking why? The answer is, because method clone performs shallow copy which does not copies child objects recursively and children objects may still point to the same objects in memory as original object's children do. As we have articulated in beginning of this article that Java cloning or shallow copy copies items up to one level.

Copying Java Array by java.lang.System.arraycopy()

Along with Java's clone() method to copy array elements from one array to another Java provides java.lang.System.arraycopy(). However, java.lang.System.arraycopy() is different from cloning; during cloning we create a duplicate copy of an array whereas in copying we copy individual elements from one array to another. Java's static method java.lang.System.arraycopy() is used to copy complete array to another and also for copying selected elements. The method arraycopy has the following signature:

public static void arraycopy(Object src,
                             int srcPos,
                             Object dest,
                             int destPos,
                             int length)

Method arraycopy() copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array. A subsequence of array components is copied from the source array referenced by src to the destination array referenced by dest. The number of components copied is equal to the length argument. The components at positions srcPos through srcPos + length - 1 in the source array are copied into positions destPos through destPos + length - 1, respectively, of the destination array.

If the src and dest arguments refer to the same array object, then the copying is performed as if the components at positions srcPos through srcPos + length - 1 were first copied to a temporary array with length components and then the contents of the temporary array were copied into positions destPos through destPos + length - 1 of the destination array.

If either or both of the arrays are null, then a NullPointerException is thrown. See java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int) for more details. Following is a small example, which demonstrates arraycopy().

/* ArrayCopyDemo.java */
// Demonstrating array copy using System.arraycopy()
public class ArrayCopyDemo
{
    public static void main(String[] args)
    {
        int[] src = new int[5];
        for (int i = 0; i < src.length; i++) 
        {
            src[i] = i + 1;
        }
        int[] dest = new int[5];
        System.arraycopy(src, 0, dest, 0, 5);
 
        System.out.println("src contents: ");
        for (int i : src)
            System.out.print(i + " ");
 
        System.out.println("\n"); //blank line
 
        System.out.println("dest contents: ");
        for (int i : dest)
            System.out.print(i + " ");
    }
}
OUTPUT
======
src contents: 
1 2 3 4 5 
 
dest contents: 
1 2 3 4 5 

The statement System.arraycopy(src, 0, dest, 0, 5); copies 5 array elements from src to dest starting from index zero.

Java Arrays: java.util.Arrays Class

The java.util.Arrays class is a member of Java Collections Framework. This class contains many useful static methods for array operations (such as sorting and searching). Methods of java.util.Arrays are static by nature because this class is a utility class, therefore creating an object is not essential to manipulate arrays by using this class.

Java Arrays: Deep Copy or Deep Cloning

In Java programming language, usually copying an object means we create another reference that eventually points to the same object in memory. This means if we made a change to one object, the other will also be affected in the same way. As we have seen so far, Java's clone() makes an independent copy but this is shallow; sub-objects still point to the originals.

During deep copying or deep cloning in Java all sub-objects of an object are recursively copied. For an instance, you have a very few options for deep cloning and with immense care. These options are Serialization, and Reflection.

Java Multidimensional Arrays

Java does not support multidimensional arrays like C language. Rather, seemingly looking Java's multidimensional arrays are indeed arrays whose components are themselves arrays. In Java it is because the all rows may or may not have same number of columns, or the size of rows may vary in length. Program EnForArrayDemo.java demonstrates this.

Another important point to note that two nested for loops won't help when all rows of a seemingly looking two dimensional array have different number of columns. The for-each variant of for loop proved to be suitable for such conditions.

//EnForArrayDemo.java
// Demonstrating accessing array elements
public class EnForArrayDemo
{
    public static void main(String[] args)
    {
        int[][] arrTwoD = new int[3][];
        arrTwoD[0] = new int[2];
        arrTwoD[1] = new int[3];
        arrTwoD[2] = new int[4];
 
        for(int[] arr : arrTwoD)
        {
            for(int elm : arr)
            {
                System.out.print(elm + " ");
            }
            System.out.println();
        }
    }
}
 
OUTPUT
======
0 0 
0 0 0 
0 0 0 0 

Java Cloning of Multidimensional Arrays

The following, example program (CloneTwoDArrayDemo.java) demonstrates how clone method works on array of arrays in Java, and what are its side effects? Following program demonstrates the inability of Java cloning that creates a duplicate copy of two dimensional array by using clone() method.

// CloneTwoDArrayDemo.java
// Demonstrating cloning of two dimensional array objects
public class CloneTwoDArrayDemo
{
  public static void main(String[] args)
  {
    int arri[][] = {{1, 2}, {3, 4}, {5, 6}};
    int cloneArri[][];
 
    //cloneArri is assigned a clone of arri
    cloneArri = arri.clone();
 
    /* nullify 0th row of cloneArri.
     * It will not effect arri, because cloneArri and
     * arri have a separate set of rows.
     */
    cloneArri[0] = null;
    System.out.println("cloneArri[0]: " + cloneArri[0]); // null
    System.out.println("arri[0]: " + arri[0]); //class name + @ + hashcode in hex
 
    System.out.println(); // blank line
 
    /* Now, assign a new value to cloneArri[1][1].
     * It will change the value of arri[1][1] also,
     * because clone() does not copy subarray
     * therefore cloneArri[1][1], and arri[1][1]
     * will have the same value.
     */
    cloneArri[1][1] = -9;
 
    System.out.println("cloneArri[1][1]: " + cloneArri[1][1]);
    System.out.println("arri[1][1]: " + arri[1][1]);
  }
}
 
OUTPUT
======
cloneArri[0]: null
arri[0]: [I@8dc8569
 
cloneArri[1][1]: -9
arri[1][1]: -9

Examine the output of CloneTwoDArrayDemo.java, and you will find that while cloning two dimensional array Java creates a shallow copy up to the rows level. That's why if we assign cloneArri[1][1] by -9, the value of arri[1][1] will also be changed to -9.

By using Java's clone() method, when a two dimensional array is cloned a new list of objects pointing to rows is created. Each object from this list further points to the same location where the original array's row object points. Therefore, when you do cloneArri[0] = null;. It has no effect on the arri[0]. Because both arrays arri and cloneArri have separate copies of row level objects. But, at one level deeper when statement cloneArri[1][1] = -9; is executed both arrays arri and cloneArri will be updated, because both arrays point to the same location when it comes to column level.

Last Word

This tutorial explained clone vs deep copy. Java cloning uses shallow copy. Hope you have enjoyed reading this tutorial. Please do write us if you have any suggestion/comment or come across any error on this page. Thanks for reading!

References



Share this page on WhatsApp

Get Free Tutorials by Email

About the Author

is the founder and main contributor for cs-fundamentals.com. He is a software professional (post graduated from BITS-Pilani) and loves writing technical articles on programming and data structures.