Java 6: Copying Typed Arrays

This article was originally published in the Javalobby Tips & Tricks section of Javalobby.org

One of the neat tricks of the Collection.toArray(Object[]) method is that it will always return an array matching the passed in type, irrespective of whether or not the one you passed in can be used to hold all of the objects in the array. That's why so often you see this idiom:

List<String> l = new ArrayList<String>();
l.add("Test1");
l.add("Test2");
l.add("Test3");
String[] result = l.toArray(new String[0]);

Even though the collection has three elements, a zero-length array is passed in as a type identifier. The toArray method is able to do this by first verifying the length of the array, and if it is not appropriate, using introspection on the array to determine the type and creating a new array. Note that this is probably the more appropriate way to perform this task, as it saves the extra processing costs in the majority of cases:

String[] result = l.toArray(new String[l.size()]);

This works out to the cost of allocating the array as opposed to the cost of allocating two arrays and introspecting the type of the passed in array.

Now, this functionality is useful, but it's kind of 'magic' since there is no real reusable way to perform the task using traditional mechanisms such as the 'new' operator. Magic is sometimes not a bad thing, however; reflection can be a very powerful and useful tool, and now-a-days most toolkits and frameworks utilize it in some fashion.

Unfortunately, to emulate the behavior of the 'toArray' method in your own code is not as simple as one would expect. Here is a snippet of code that performs effectively the same 'type safe' copy of an array:

private Object[] arrayCopy(Object[] original) {
	Class arrayType = original.getClass().getComponentType();
	Object[] copy = (Object[])java.lang.reflect.Array.newInstance(arrayType, original.length);
	System.arraycopy(original, 0, copy, 0, original.length);
	return copy;
}

As you can see, this could be simpler. This type of array copy becomes more complicated and potentially irritating with generics:

@SuppressWarnings("unchecked")
private <T> T[] arrayCopy(T[] original) {
	Class<?> arrayType = original.getClass().getComponentType();
	T[] copy = (T[])java.lang.reflect.Array.newInstance(arrayType, original.length);
	System.arraycopy(original, 0, copy, 0, original.length);
	return copy;
}

The 'suppress warnings' call is necessary if you want to get rid of compiler complaints due to the loss of type parameter precision via reflection.

Java 6 has added a suite of utility methods to handle this scenario that all play well with Generics, and they have also supplied the primitive value counterparts. In general, there are two categories of methods: copyOf(...) and copyOfRange(...) .

String[] originalArray = new String[3];
originalArray[0] = "Test1";
originalArray[1] = "Test1";
originalArray[2] = "Test1";
String[] copy = Arrays.copyOf(originalArray, originalArray.length);
Object[] copy2 = Arrays.copyOf(originalArray, originalArray.length, Object[].class);
String[] copy3 = Arrays.copyOfRange(originalArray, 0, 1);
Object[] copy4 = Arrays.copyOfRange(originalArray, 0, 1, Object[].class);

As you can see from the example, with both copy methods, you have the option of passing an array type you would like to be returned (as opposed to the type of the original array). The type you pass in must be a super-class of the type of the original array.