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);
}
}
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.