I noticed that in Java Array.newInstance()
returns Object
, rather than T[]
. It is understandable as this method was introduced before Java supports generic types.
However it is a surprise that there are no equivalent generic version of this. Java 7's Arrays.copyOf
is not the same - it copies the content of the parameter, rather than creating a new dummy array (with all null objects inside).
Since implementation of this seems trivial, are there any reason not adding it into the JRE? or I just cannot find one?
UPDATE
It seems I shall provide my own "trivial" implementation to stop misunderstand of the question.
class MyArrayUtil {
//Generic version for classes
@SuppressWarnings("unchecked")
public static <T> T[] newArrayOf(T[] t, int len){
return (T[]) Array.newInstance(t.getClass().getComponentType(), len);
}
//For array of int
public static int[] newArrayOf(int[] t, int len){
return new int[len];
}
//For other primitive types...
}
I am not posting this code as an answer because it is not the answer of the question. The question is for reason and/or existing code, not how to implement.
UPDATE
I have updated the code to make it similar to Arrays.copyOf
, and the advantage is the programmer can simply change the type of the parameter to adjust the code for another type. Also I eliminated the use of Array.newInstance
for primitive types.
An important difference between arrays and generics is how they enforce type checking. Specifically, arrays store and check type information at runtime. Generics, however, check for type errors at compile-time and don't have type information at runtime. Java's syntax suggests we might be able to create a new generic array:
Although we can't initialize generic arrays directly, it's still possible to achieve the equivalent operation if the precise type of information is provided by the calling code. 3. Creating a Generic Array For our example, let's consider a bounded stack data structure, MyStack, where the capacity is fixed to a certain size.
The second parameter specifies how much space to create for the array. As the result of Array#newInstance is of type Object, we need to cast it to E [] to create our generic array. We should also note the convention of naming a type parameter clazz, rather than class, which is a reserved word in Java.
As we'd like the stack to work with any type, a reasonable implementation choice would be a generic array. First, we'll create a field to store the elements of our stack, which is a generic array of type E: public MyStack(Class<E> clazz, int capacity) { elements = (E []) Array.newInstance (clazz, capacity); }
Guava provides just such a function. It's not the first time Guava (or Apache Commons) provided a commonly-used helper that the JDK doesn't have, for whatever reason.
You may know this, but some background for the googler who stumbles upon this in the future: The reason the signature can't be made generic is that the method Array.newInstance
returned Object
in Java 1.4, so for backwards compatibility, the raw version of the method should also return Object
. If it had been generified as:
<T> T[] newInstance(Class<T> componentType, int length)
...then the return type would be Object[]
, not Object
. This would break backwards compatibility, which the Java designers have always tried very hard not to do.
The Arrays.copyOf
methods only came in with Java 1.6, and thus didn't have to worry about backwards compatibility.
No, you need to pass the concrete type as a parameter one way or the other. As you mentioned, Arrays.copyOf
shows this in action.
Class<T> type = determinteTheTypeSomehow();
return (T[]) Array.newInstance(type, length);
The basic reason that Array.newInstance()
cannot be declared like <T> T[] newInstance(Class<T> class, int size)
is because it can be used to create arrays of primitives. So for example, if you pass in int.class
, which has type Class<Integer>
, then from the declaration you would expect it to return an Integer[]
object. However, the function actually returns an int[]
object, which is not a subtype of Integer[]
, so it has the wrong type.
Sure, they could add an additional method like newReferenceArrayInstance()
that prohibits primitive types (e.g. throws an exception when passed a primitive type) and thus can safely be declared to return T[]
. However, that seems like adding a completely redundant method solely for avoiding an unchecked cast.
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