What is Arrays.copyOf() method in Java?

Java class java.util.Arrays provides a method called Arrays.copyOf() that returns a copy of an array passed as a parameter to this function, followed by specifying its size. Here’s the method header for quick understanding.

Arrays.copyOf(int[] templateArray, int length);
Note that the second parameter “length” is the size of the copy array you want to create. So here we can have 3 cases.
  • The lengths of both template & copy arrays are the same.
  • The length of the copy array is greater than the length of the template array.
  • The length of the copy array is lesser than the length of the template array.
Let’s look at the coding example to see how we can handle all three scenarios mentioned above. Arrays.copyOf() Method in Java - 1

Coding Example


import java.util.Arrays;
public class ArraysCopyOfMethod {
	public static void main(String[] args) {
		
	  // Initialize your templateArray which you want a copy of
        int[] templateArray = new int[] {1, 2, 3, 4, 5, 6};  
        System.out.println("Template Array: " + Arrays.toString(templateArray)); 
        	    
        // Create a "copy" of template array using 
        // Arrays.copyOf(int[] array, int arrayLength) method 
        
        // CASE 1: Sizes of both template & copy arrays are same
        int[] copyArray1 = Arrays.copyOf(templateArray, templateArray.length);
        System.out.println("Copy Array 1: " + Arrays.toString(copyArray1));
      
        // CASE 2: Size of copy array > Size of template array
        // extra space in copy array is filled with zeros
        int[] copyArray2 = Arrays.copyOf(templateArray, 10);
        System.out.println("Copy Array 2: " + Arrays.toString(copyArray2));
  
        // CASE 3: Size of copy array < Size of template array
        // copy array is only filled with only elements in overlapping size
        int[] copyArray3 = Arrays.copyOf(templateArray, 3);
        System.out.println("Copy Array 3: " + Arrays.toString(copyArray3));
	}

}

Output

Template Array: [1, 2, 3, 4, 5, 6] Copy Array 1: [1, 2, 3, 4, 5, 6] Copy Array 2: [1, 2, 3, 4, 5, 6, 0, 0, 0, 0] Copy Array 3: [1, 2, 3]

Copying 2D Arrays Using Loops

Copying 2D arrays manually using loops ensures greater control and enables deep copying, which creates new instances of nested arrays.

Example: Manual Copy of 2D Arrays

import java.util.Arrays;

public class ManualCopyExample {
    public static void main(String[] args) {
        int[][] original = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };

        int[][] copy = new int[original.length][];

        for (int i = 0; i < original.length; i++) {
            copy[i] = Arrays.copyOf(original[i], original[i].length);
        }

        System.out.println("Original: " + Arrays.deepToString(original));
        System.out.println("Copy: " + Arrays.deepToString(copy));
    }
}
    

Output:

 Original: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 Copy: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Challenges and Pitfalls: Shallow vs. Deep Copying

When copying arrays, understanding the distinction between shallow and deep copying is crucial:

  • Shallow Copy: Copies only the references of nested arrays, not the actual elements. Modifying one array affects the other.
  • Deep Copy: Creates new instances of nested arrays, ensuring changes to one array do not affect the other.

Using Arrays.copyOf() for 2D arrays performs a shallow copy, which may lead to unintended consequences.

Using Built-In Methods for Copying 2D Arrays

Shallow Copy with Arrays.copyOf()

int[][] shallowCopy = Arrays.copyOf(original, original.length);

While this copies the outer array, the nested arrays remain shared, leading to potential issues if modified.

Deep Copy with Loops

The manual method described earlier ensures a deep copy, preventing unintended modifications.

Using External Libraries for Array Copying

Apache Commons: SerializationUtils.clone()

The Apache Commons library offers a straightforward way to deep copy arrays using serialization:

import org.apache.commons.lang3.SerializationUtils;

int[][] deepCopy = SerializationUtils.clone(original);

This method works for arrays of objects that implement Serializable.

Apache Commons: ArrayUtils

The ArrayUtils class provides various utilities for array manipulation, including deep copying.

import org.apache.commons.lang3.ArrayUtils;

int[][] deepCopy = ArrayUtils.clone(original);

Importance of Deep Copying with Non-Primitive Types

When working with arrays of non-primitive types, shallow copying only duplicates references. This can lead to shared state issues where modifying one element affects others.

Example:

class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Point[][] points = {
    {new Point(1, 2), new Point(3, 4)},
    {new Point(5, 6), new Point(7, 8)}
};

// Deep copying with loops or serialization ensures independence of Point objects.

Using Loops for Manual Array Copying

While Arrays.copyOf() simplifies array copying, using loops offers greater control and flexibility. This method allows developers to customize the copying process, such as skipping certain elements or applying transformations during the copy.

Example: Copying a 1D Array with Loops

public class ManualCopyExample {
    public static void main(String[] args) {
        int[] original = {1, 2, 3, 4, 5};
        int[] copy = new int[original.length];

        for (int i = 0; i < original.length; i++) {
            copy[i] = original[i];
        }

        System.out.println("Original: " + java.util.Arrays.toString(original));
        System.out.println("Copy: " + java.util.Arrays.toString(copy));
    }
}

Output:

 Original: [1, 2, 3, 4, 5]
 Copy: [1, 2, 3, 4, 5]

Example: Copying a 2D Array with Loops

For multidimensional arrays, nested loops are used to copy each nested array:

public class ManualCopy2DExample {
    public static void main(String[] args) {
        int[][] original = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };

        int[][] copy = new int[original.length][];

        for (int i = 0; i < original.length; i++) {
            copy[i] = new int[original[i].length];
            for (int j = 0; j < original[i].length; j++) {
                copy[i][j] = original[i][j];
            }
        }

        System.out.println("Original: " + java.util.Arrays.deepToString(original));
        System.out.println("Copy: " + java.util.Arrays.deepToString(copy));
    }
}

Output:

 Original: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 Copy: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Performance Considerations: Loops vs. Built-in Methods

When deciding between loops and built-in methods for array copying, consider the following factors:

  • Small Arrays: Loops may be faster for small arrays due to reduced overhead compared to built-in methods like Arrays.copyOf().
  • Large Arrays: Built-in methods are optimized and can leverage low-level system optimizations, making them faster for large arrays.
  • Customization: Loops offer greater flexibility for custom copying requirements, such as filtering or transforming elements during the copy process.

Benchmark Example

import java.util.Arrays;

public class PerformanceComparison {
    public static void main(String[] args) {
        int[] original = new int[100000];
        Arrays.fill(original, 42);

        // Measure time for manual copy
        long start = System.nanoTime();
        int[] manualCopy = new int[original.length];
        for (int i = 0; i < original.length; i++) {
            manualCopy[i] = original[i];
        }
        long end = System.nanoTime();
        System.out.println("Manual copy time: " + (end - start) + " ns");

        // Measure time for Arrays.copyOf()
        start = System.nanoTime();
        int[] builtInCopy = Arrays.copyOf(original, original.length);
        end = System.nanoTime();
        System.out.println("Built-in copy time: " + (end - start) + " ns");
    }
}

Understanding System.arraycopy

The System.arraycopy method is a low-level array copying utility provided by Java. It offers efficient copying by utilizing native system calls, making it one of the fastest methods available.

Method Signature:

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

Parameters:

  • src: The source array from which elements are copied.
  • srcPos: The starting position in the source array.
  • dest: The destination array to which elements are copied.
  • destPos: The starting position in the destination array.
  • length: The number of elements to copy.

Example: Basic Array Copying

public class BasicArrayCopy {
    public static void main(String[] args) {
        int[] source = {1, 2, 3, 4, 5};
        int[] destination = new int[5];

        System.arraycopy(source, 0, destination, 0, source.length);

        System.out.println("Source: " + java.util.Arrays.toString(source));
        System.out.println("Destination: " + java.util.Arrays.toString(destination));
    }
}

Output:

 Source: [1, 2, 3, 4, 5]
 Destination: [1, 2, 3, 4, 5]

Flexibility and Efficiency of System.arraycopy

System.arraycopy is preferred over other methods for its:

  • Speed: Leveraging native system calls makes it faster than manual copying or Arrays.copyOf().
  • Flexibility: Allows partial copying and precise control over the source and destination indices.
  • Versatility: Can handle multi-dimensional arrays and custom copying scenarios efficiently.

Example: Partial Array Copying

public class PartialArrayCopy {
    public static void main(String[] args) {
        int[] source = {10, 20, 30, 40, 50};
        int[] destination = new int[3];

        System.arraycopy(source, 1, destination, 0, 3);

        System.out.println("Source: " + java.util.Arrays.toString(source));
        System.out.println("Destination: " + java.util.Arrays.toString(destination));
    }
}

Output:

 Source: [10, 20, 30, 40, 50]
 Destination: [20, 30, 40]

Example: Copying Between Different Array Segments

public class CopySegments {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6};

        // Shift elements within the same array
        System.arraycopy(array, 2, array, 1, 3);

        System.out.println("Modified Array: " + java.util.Arrays.toString(array));
    }
}

Output:

 Modified Array: [1, 3, 4, 5, 5, 6]

Limitations and Precautions

  • Type Matching: The source and destination arrays must be compatible in type; otherwise, an ArrayStoreException will be thrown.
  • Index Validation: Ensure valid indices to avoid IndexOutOfBoundsException.
  • Non-Primitive Arrays: For object arrays, shallow copies are performed. Use deep copying for nested objects.

Conclusion

By now you must have a logical grasp over the Arrays.copyOf() method in Java. However, feel free to experiment with different inputs to fuel your curiosity.