There are several ways to copy an array :
- use the various copyOf and copyOfRange methods of the Arrays class - probably the simplest method
- use System.arraycopy - useful when copying parts of an array
- call its clone method, and do a cast - the simplest style, but only a shallow clone is performed
- use a for loop - more than one line, and needs a loop index
This example class demonstrates
- relative performance of the various methods
- how clone is a shallow copy, and leads to independent storage only for primitive, one dimensional arrays.
import java.util.*; public final class ArrayCopier { public static void main (String... aArguments) { String action = aArguments[0]; int numIterations = 0; if ( aArguments.length == 2 ) { numIterations = Integer.parseInt( aArguments[1] ); } if ( action.equals("performance") ) { demoPerformance( numIterations ); } else if ( action.equals("storage") ) { demoIndependanceOfStorage(); } } /** * Display the time it takes to copy an array in various ways. */ private static void demoPerformance( int aNumIterations ){ Stopwatch stopwatch = new Stopwatch(); int[] numbers = {1,2,3,4,5,6,7,8,9,10}; stopwatch.start(); copyUsingClone( numbers, aNumIterations ); stopwatch.stop(); System.out.println("Using clone: " + stopwatch); stopwatch.start(); copyUsingArraycopy( numbers, aNumIterations ); stopwatch.stop(); System.out.println("Using System.arraycopy: " + stopwatch); stopwatch.start(); copyUsingArraysCopyOf( numbers, aNumIterations ); stopwatch.stop(); System.out.println("Using Arrays.copyOf: " + stopwatch); stopwatch.start(); copyUsingForLoop( numbers, aNumIterations ); stopwatch.stop(); System.out.println("Using for loop: " + stopwatch); } private static void copyUsingClone( int[] aArray , int aNumIterations) { for ( int idx = 0 ; idx < aNumIterations; ++idx ) { int[] copy = (int[])aArray.clone(); } } private static void copyUsingArraycopy( int[] aArray , int aNumIterations) { for ( int idx = 0 ; idx < aNumIterations; ++idx ) { int [] copy = new int[aArray.length]; System.arraycopy( aArray, 0, copy, 0, aArray.length ); } } private static void copyUsingArraysCopyOf( int[] aArray , int aNumIterations) { for ( int idx = 0 ; idx < aNumIterations; ++idx ) { int[] copy = Arrays.copyOf(aArray, aArray.length); } } private static void copyUsingForLoop( int[] aArray , int aNumIterations) { for ( int iterIdx = 0 ; iterIdx < aNumIterations; ++iterIdx ) { int [] copy = new int[aArray.length]; for ( int idx = 0; idx < aArray.length; ++idx ) { copy[idx] = aArray[idx]; } } } /** * (The for-loop and System.arraycopy styles clearly have independent * storage, and are not exercised in this method.) */ private static void demoIndependanceOfStorage() { //a clone of a one-dimensional array has independent storage int[] numbers = {1,1,1,1}; int[] numbersClone = (int[])numbers.clone(); //set 0th element to 0, and compare numbersClone[0] = 0; System.out.println("Altered clone has NOT affected original:"); System.out.println("numbersClone[0]: " + numbersClone[0] ); System.out.println("numbers[0]: " + numbers[0] ); //the clone of a multi-dimensional array does *not* have //independant storage int[][] matrix = { {1,1}, {1,1} }; int[][] matrixClone = (int[][])matrix.clone(); //set 0-0th element to 0, and compare matrixClone[0][0] = 0; System.out.println("Altered clone has affected original:"); System.out.println("matrixClone element 0-0:" + matrixClone[0][0]); System.out.println("matrix element 0-0: " + matrix[0][0]); //the clone of an array of objects as well is only shallow Date[] dates = { new Date() }; System.out.println("Original date: " + dates[0]); Date[] datesClone = (Date[])dates.clone(); datesClone[0].setTime(0); System.out.println("Altered clone has affected original:"); System.out.println("datesClone[0]:" + datesClone[0]); System.out.println("dates[0]: " + dates[0]); } }
System.arraycopy seems to have slightly better performance. Differences between the various styles are small, however, and would often be regarded as a micro-optimization :
>java -cp . -Xint ArrayCopier performance 250000
Using clone: 93 ms
Using System.arraycopy: 110 ms
Using Arrays.copyOf: 187 ms
Using for loop: 422 ms
The above example use the -Xint option to turn off the Just In Time compiler. Here, bytecodes are interpreted at runtime, but never compiled by the HotSpot compiler into native code. This provides a uniform environment for executing tests of relative execution time, since there is no "warm-up" period.
Example run demonstrating independence of storage, or lack thereof :
>java -cp . ArrayCopier storage
Altered clone has NOT affected original:
numbersClone[0]: 0
numbers[0]: 1
Altered clone has affected original:
matrixClone element 0-0:0
matrix element 0-0: 0
Original date: Mon Sep 30 15:47:58 EDT 2002
Altered clone has affected original:
datesClone[0]:Wed Dec 31 19:00:00 EST 1969
dates[0]: Wed Dec 31 19:00:00 EST 1969
|
|