我有一个Java JUnit 4测试和一个创建通用数组的泛型类。当我创建一个返回此通用数组的方法时,我会在返回它时收到错误消息。如果我将ArrayList(其中T是通过类实例化的Byte)返回到ArrayList,它就可以工作。
为什么数组似乎是实例化的和可用的(在更复杂的类上测试)但我不能返回对该数组的引用?
错误:
java.lang.ClassCastException: [Lcom.waikato.assignment.Object; cannot be cast to [Ljava.lang.Byte;
at com.waikato.testing.TestJava.test(TestJava.java:20)
类别:
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;
}
}
测试
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);
}
}
答案 0 :(得分:5)
可以通过反射构建“通用”数组:
T[] array = (T[]) Array.newInstance(Byte.class, 32)
将Byte.class
替换为对所需类的引用。换句话说:
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;
}
}
您可以这样验证:
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));
}
由于类型擦除,如果不使用Class<?>
对象作为构造函数参数,则无法解决此问题。
答案 1 :(得分:2)
array = (T[]) new TestClass[32];
对我来说这看起来不像Byte[]
,编译器应该警告你在运行时忽略了通用转换。
这是通用解决方案
TestClass(Class<T> tclass){
//create an array for the generic type
array = (T[])java.lang.reflect.Array.newInstance(tclass,32);
}
TestClass<Byte> bTest = new TestClass(Byte.class);
答案 2 :(得分:1)
有一种方法可以找出通用类型类的实际类型参数。
我刚刚为Main类更改了这样的构造函数。
public class TestClass<T> {
T[] array;
@SuppressWarnings("unchecked")
public TestClass() {
Class<T> objClass;
objClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; // Found the type paramenter
array = (T[]) Array.newInstance( objClass, 32);
}
public T[] getArray() {
return array;
}
public boolean doThing() {
T[] t = array;
return t == array && t != null;
} }
和测试方法..
@Test
public void test() {
TestClass<Byte> t = new TestClass<Byte>(){}; // Added {}
Byte[] b = t.getArray();
Assert.assertTrue(t.doThing());
Assert.assertTrue(b.length != 0);
}
答案 3 :(得分:0)
这一行错了:
public TestClass() {
array = (T[]) new TestClass[32];
}
这与你的问题的标题相矛盾,即“T是Byte”,因为T被初始化为TestClass。
一个想法是将数组更改为List&lt; T&gt;。