3

我有一个 Java JUnit 4 测试和一个创建泛型数组的泛型类。当我创建一个方法来返回这个通用数组时,我在返回它时收到一条错误消息。如果我将一个 ArrayList(其中 T 是按类实例化的字节)返回一个 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);
    }

}
4

4 回答 4

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<?>由于类型擦除,如果不使用对象作为构造函数参数,则无法解决此问题。

于 2012-04-26T09:18:19.200 回答
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);
于 2012-04-26T09:21:04.150 回答
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);
}
于 2012-04-26T09:51:28.447 回答
0

这一行是错误的:

public TestClass() {
    array = (T[]) new TestClass[32];
}

这与您的问题的标题相矛盾,即“T 是字节的位置”,因为 T 被初始化为 TestClass。

一种想法是将数组更改为 List<T>。

于 2012-04-26T09:14:52.367 回答