views:

226

answers:

3

Which is the best practice in this situation? I would like an un-initialized array of the same type and length as the original.

public static <AnyType extends Comparable<? super AnyType>> void someFunction(AnyType[] someArray) {

    AnyType[] anotherArray = (AnyType[]) new Comparable[someArray.length];
     ...or...
    AnyType[] anotherArray = (AnyType[]) new Object[someArray.length];

    ...some other code...
}

Thanks, CB

+4  A: 

Arrays and generics don't really mix that well. That's because arrays are covariant and generics are not. Let me give you an example:

public static void main(String args[]) {
  foo(new Float[1]);
}

public static void foo(Number[] n) {
  n[0] = 3;
}

That code compiles but will result in an ArrayStoreException.

So the issue you'll have in recreating that array is that it may not be an array of AnyType but it might be a subclass of AnyType. You could of course use someArray.getClass() and create the array with reflection.

The overall theme however is that you should favour Lists over arrays because Lists don't have te same problems. Change the code to:

public static void main(String args[]) {
  foo(new ArrayList<Float>());
}

public static void foo(List<Number> list) {
  list.add(3);
}

And the code won't compile, which is a far better outcome.

cletus
+5  A: 
AnyType[] anotherArray = (AnyType[])java.lang.reflect.Array.newInstance(
      someArray.getClass().getComponentType(), someArray.length);
Dimitris Andreou
It should be pointed out that this creates an array whose base type is the same as the base type of the input array. This is *not necessarily the same* as the generic type parameter that will be inferred by the compiler.
Stephen C
Also note that this is true for the input "someArray" too. The created "anotherArray" can store instances of "AnyType" exactly as safely as "someArray" can. So this code doesn't add any restriction that was not already there.
Dimitris Andreou
+3  A: 

A good reference is to see how <T> T[] Collection.toArray(T[]) is implemented by AbstractCollection:

public <T> T[] toArray(T[] a) {
    // Estimate size of array; be prepared to see more or fewer elements
    int size = size();
    T[] r = a.length >= size ? a :
              (T[])java.lang.reflect.Array
              .newInstance(a.getClass().getComponentType(), size);
    //...

So the technique uses:

If you absolutely must create a "generic" array, then this technique of passing an instanceof T[] and using reflection to instantiate another is the way exemplified by Java Collections Framework.

However, you must also question if you really need such functionality.

From Effective Java 2nd Edition: Item 25: Prefer lists to arrays:

In summary, arrays and generics have very different type rules. Arrays are covariant and reified, generics are invariant and erased. As consequence, arrays provide runtime type safety but not compile-time type safety and vice versa for generics. Generally speaking, arrays and generics don't mix well. If you find yourself mixing them and getting compile-time errors and warnings, your first impulse should be to replace the arrays with lists.

You should read the whole item for a more comprehensive treatment of the subject.

polygenelubricants