2

Possible Duplicate:
Creating generic arrays in Java

I want to trim a generic array of objects down to only the first len elements. This seems like it should work:

@SuppressWarnings("unchecked")
public static <T> T[] trimArray(T[] data, int len){
    T[] result = (T[]) new Object[len];
    System.arraycopy(data, 0, result, 0, len);
    return result;
}

But it throws a ClassCastException if I do something like

public class Foo{

    double f;

    public Foo(double f){
    this.f = f;
    }

}

public static void main(String[] args){

    Foo[] A = new Foo[10];
    A[0]= new Foo(1);
    A[1]= new Foo(2);
    A[2]= new Foo(3);
    Foo[] B = trimArray(A, 3);

}

I don't understand why this won't work, but something similar does in java generic casting in generic classes

Community
  • 1
  • 1
andyInCambridge
  • 1,065
  • 2
  • 12
  • 25

2 Answers2

11

The JDK already has a builtin for this:

Foo[] B = Arrays.copyOf(A, 3);

Javadoc (since 1.6)

Note however that it will also expand the array (padded with nulls) if the source array length is less than the wanted length. You can easily work around this by using, for instance:

Foo[] B = Arrays.copyOf(A, Math.min(3, A.length));
fge
  • 110,072
  • 26
  • 223
  • 312
1

This happens because Arrays are covariant, meaning you can treat an Array of a subtype freely as an array of the supertype, but the opposite isn't true.

What you can do, although it's an ugly hack, is return an Object[] and then cast each element to T (the actual elements in the array are covariant, but the array itself is not), as needed, but I would strongly advise against it.

Use the builtins recommended in another answers, like Arrays.copyOf.

In case you're wondering why, it's because this would break type safety too easily.

For instance:

Object[] bla = new Object[10];
bla[0] = new Integer(2);
bla[1] = "stillanObject";

You have an array of objects, perfectly valid.

Now you cast it to, say, an array of strings...

return (String[])bla;

And hell would be unleashed upon the JVM, you would actually have an Array that should be of type String containing String and Integer objects! \

Type safety is a good thing.

UPDATE:

Just to add one more detail, you can cast String[] to Object[], but this may incur in an ArrayStoreException if you try to store anything that is not a String (or type of original array). Reading the original array as Object[] is perfectly safe though.

pcalcao
  • 15,237
  • 1
  • 40
  • 62
  • From WP: "covariant: converting from a specialized type (Cats) to a more general type (Animals): Every cat is an animal." Now, you convert from more general (Object) to more special (String). And call it covariant. Are you sure? – Val Dec 30 '12 at 18:14
  • You're right, I switched up terms there, should be fixed. – pcalcao Dec 30 '12 at 18:20