Search code examples
javaarraysgenericsjava-6

Returning T[] (where T is Byte[]) to Byte[]


I have a Java JUnit 4 test and a generic class which creates a generic array. When I create a method to return this generic array I get an error message upon returning it. It works if I return an ArrayList (where T is Byte by class instantiation) to an ArrayList.

Why is it that the array appears to be instantiated and usable (tested on more complex classes) yet I can't return a reference to that array?

Error:

java.lang.ClassCastException: [Lcom.waikato.assignment.Object; cannot be cast to [Ljava.lang.Byte;
at com.waikato.testing.TestJava.test(TestJava.java:20)

Class:

public class TestClass<T> {
    T[] array;

    @SuppressWarnings("unchecked")
    public TestClass() {
        array = (T[]) new Object[32];
    }

    public T[] getArray() {
        return array;
    }

    public boolean doThing() {
        T[] t = array;

        return t == array && t != null;
    }
}

Test:

public class TestJava {

    @Test
    public void test() {
        TestClass<Byte> t = new TestClass<Byte>();
        Byte[] b = t.getArray(); // Crash caused

        assertTrue(t.doThing()); // Works when above line is removed.
        assertTrue(b.length != 0);
    }

}

Solution

  • A "generic" array can be constructed via reflection:

    T[] array = (T[]) Array.newInstance(Byte.class, 32)
    

    Replace Byte.class by a reference to the desired class. In other words:

    public class TestClass<T> {
        T[] array;
    
        @SuppressWarnings("unchecked")
        public TestClass(Class<T> type) {
            array = (T[]) Array.newInstance(type, 32);
        }
    
        public T[] getArray() {
            return array;
        }
    
        public boolean doThing() {
            T[] t = array;
    
            return t == array && t != null;
        }
    }
    

    You can verify this as such:

    public static void main(String[] args) {
        TestClass<Byte> test = new TestClass<Byte>(Byte.class);
        // No ClassCastException here
        Byte[] array = test.getArray();
        System.out.println(Arrays.asList(array));
    }
    

    Due to type erasure, you cannot solve this problem without resorting to a Class<?> object as a constructor argument.