0

The following snippet makes sense yet when I run this against my unit test.. I get a ClassCastException (Object can't be cast to String) on the line marked with '>>>>'. Can this type of operation be done in a generic ?

public class ArrayUtils<E> {

    public static <E> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        for(int i=0; i < array.length; i++ ) {
            result[i] = array[i];
        }
        result[result.length-1] = item;
        return result;
    }

}

   @Test
   public void testAppendToArray() {
       String[] array = new String[1];
       array[0] = "a";

       assertSame("Array is not correct length.", 1, array.length );
>>>>   String[] appendToArray = ArrayUtils.<String>appendToArray(array, "b");
       assertSame("Array is not correct length.", 2, appendToArray.length );
    }
Chris Johnson
  • 2,271
  • 2
  • 16
  • 17

5 Answers5

5

You should not create your array using new Object[]. You should use Array.newInstance(Class clazz, int length) instead.

AlexR
  • 109,181
  • 14
  • 116
  • 194
1

you're casting Object to String, IOW, a super class to the inherited one. It is always prohibited. As AlexR suggested, make use of Arrays.newInstance(). But in that case you would have to pass a class of your object as here:

ArrayUtils.<String>append(array, "b", String.class);

I suggest you not to try implementing this standard behaviour of dynamically extended array : it has been already implemented in ArrayList class. You can checkout the source to learn how it is dealing with generics.

Vladimir Ivanov
  • 41,277
  • 17
  • 74
  • 99
0

I don't know what is this code for, but it puts burden to the garbage collector, since to add one element, you allocate a new array. You should use any implementation of List for this, for example, ArrayList.

khachik
  • 26,041
  • 7
  • 52
  • 90
0

Unfortunately there is no way to dynamically create an array of generic type in Java, because information related to generic type (E) is not carried at run-time, so there is no way to know what type of array to create.

To solve the problem I would suggest a similar solution to the one used in collections library

T[] java.util.List.toArray(T[] array)

method. That is, instead of creating a new array inside your appendToArray function, pass it from outside. That is:

public static <E> E[] appendToArray(E[] array, E item, E[] newArray) {
  ... your code ...
}

@Test
public void test(){
  appendToArray(array, "b", new String[array.length+1]);
}

I know this does not looks as nice as other solutions, but it's type safe, and has better performance because it does not resort to reflection. For this very reason you are recommended to use

T[] java.util.List.toArray(T[] array)

method over it's reflection equivalent

T[] java.util.List.toArray()
rodion
  • 13,913
  • 3
  • 49
  • 55
0

As others have said, you should use Array.newInstance() to create an instance of the array of the correct type. What is more helpful is that you can get the component type you need out of the class of the original array.

Also, I simplified the copying by using System.arraycopy().

public static <E> E[] appendToArray(E[] array, E item) {
    E[] result = (E[])java.lang.reflect.Array.newInstance(array.getClass().getComponentType(), array.length+1);
    System.arraycopy(array, 0, result, 0, array.length);
    result[result.length-1] = item;
    return result;
}

In Java 1.6+, you can just do this:

public static <E> E[] appendToArray(E[] array, E item) {
    E[] result = java.util.Arrays.copyOf(array, array.length+1);
    result[result.length-1] = item;
    return result;
}
newacct
  • 110,405
  • 27
  • 152
  • 217