I have trouble understanding the source code of Arrays.copyOf
.
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
what is this line checking?
(Object)newType == (Object)Object[].class
What are the differences between (T[]) new Object[newLength]
and (T[]) Array.newInstance(newType.getComponentType(), newLength)
. why Array.newInstance
not good enough for both cases?
This following line compiles, but crashes at run time (as expected). When should I use this method?
Integer[] nums = Arrays.copyOf(new String[]{"a", "b"}, 2, Integer[].class)
With arrays of primitive data the Arrays. copyOf(..) method can't copy references as these are not used for primitives. It just copies the source element values into the target elements.
Arrays. copyOf() method copies specified array into a new array with specified length. If length of new array is greater than that of source array, copyOf() method copies the whole source array to new array and pads the new array with zeros, at end, to match the specified length of new array.
arraycopy() simply copies values from the source array to the destination, Arrays. copyOf() also creates new array. If necessary, it will truncate or pad the content.
What is this line checking?
(Object)newType == (Object)Object[].class
It's checking simple equality (likely for the purpose of a micro-optimization, but more on that later).
The unusual casting is necessary because Class<Object[]>
(the type of Object[].class
) and Class<? extends T[]>
are incomparable types. Basically, for an equality comparison with ==
to compile, one of the sides has to be a subtype or supertype of the other.
I.e. we can't do:
// doesn't compile // this expression can never evaluate to true (new Integer(0) == new Float(0f))
The rules for generic types are a bit more complicated and there are a few cases where a comparison doesn't compile, but it may still evaluate to true.
The reason Class<Object[]>
is not a supertype of Class<? extends T[]>
, despite Object[]
being a supertype of all object array types, is that Java generics are invariant without the presence of a wildcard.
Another way to do the comparison would be:
(newType == (Class<? extends Object[]>)Object[].class)
What are the differences between
(T[]) new Object[newLength]
and(T[]) Array.newInstance(newType.getComponentType(), newLength)
?
new Object[...]
creates an array the normal way, of a type that is statically known. Remember, the code has just checked that T[]
is Object[]
.Array.newInstance(...)
uses reflection to dynamically create an array of the Class
type passed in.Why
Array.newInstance
not good enough for both cases?
An operation using reflection is generally slower than its non-reflective counterpart.
The reflection tutorial says:
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
Java SE is filled with micro-optimization like this. The writers of SE try to squeeze everything they can out of it.
But I wouldn't be worried about a performance hit in this case: newInstance
and copyOf
are HotSpot intrinsics. This means that ideally calls to these methods get replaced with machine-specific assembly. Anecdotally, I ran some tests and found the difference between new Object[...]
and Array.newInstance(...)
to be negligible. The code in the question is probably a relic, although it may still be useful on less well-equipped JVMs.
Reflection can also be disabled in certain contexts with strict security (such as an applet), but not typically for a normal desktop application.
When should I use this method?
In general, you will probably never use this overload. This overload is only useful if you want to change the type of the array.
Widening:
Object[] a = Arrays.copyOf( new String[] { "hello", "world" }, 3, Object[].class); a[2] = Character.valueOf('!'); System.out.println(Arrays.toString(a));
Narrowing:
String[] a = Arrays.copyOf( new Object[] { "hello", "world" }, 2, String[].class); System.out.println(String.join(" ", a));
It's more typical to use Arrays.copyOf(T[], int)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With