有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java将T[](其中T是字节[])返回到字节[]

我有一个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) 个答案

  1. # 1 楼答案

    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. # 2 楼答案

    有一种方法可以找出泛型类型类的实际类型参数

    我只是改变了主类的构造函数

    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. # 3 楼答案

    这句话错了:

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

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

    一个想法是将数组更改为列表<;T>

  4. # 4 楼答案

    “通用”数组可以通过反射构造:

    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<?>对象作为构造函数参数,就无法解决此问题