This question already has answers here:
What's the reason I can't create generic array types in Java?
                                
                                    (16个答案)
                                
                        
                                4年前关闭。
            
                    
我正在为Java中期学习,但是我对reified类型有一些问题。这里有一个错误的课,但我不明白为什么。有人可以帮我,也许给我一些解释吗?该错误当然与确定类型有关。

class Conversion {
    public static <T> T[] toArray(Collection<T> c) {
        T[] a = new T[c.size()];
        int i = 0;
        for (T x: c) a[i++] = x;
        return a;
   }
}

最佳答案

数组是一种修饰类型。这意味着在运行时知道数组的确切类型。因此,在运行时,例如String[]Integer[]之间是有区别的。

泛型不是这种情况。泛型是一个编译时构造:它们用于在编译时检查类型,但是在运行时,确切的类型不再可用。在运行时,类型参数只是Object(或者,如果类型参数有上限,则为上限)。因此,在运行时,Collection<String>Collection<Integer>的类型没有区别。

现在,当您要创建类型参数的数组时出现问题。在运行时未知T是什么,因此如果编写new T[10],则Java运行时将不知道要创建哪种数组,即String[]Integer[]。这就是为什么您不能以这种方式创建数组的原因。

有一些变通办法,没有一个完全令人满意。通常的解决方案是创建一个Object[],并将其转换为所需的数组类型:

T[] theArray = (T[]) new Object[size];


但是,您必须记住,这是非常不安全的。仅当创建的箭头的范围较小时才应执行此操作,以便可以手动确保该数组仅包含T实例,并且永远不会分配给无法容纳该数组的任何对象。以下代码演示了该问题:

public class Foo<T extends Comparable> {
    T[] createArray() {
        return (T[])new Object[1];
    }

    public static void main(String... args) {
        Foo<String> foo = new Foo<>();
        String[] ss = foo.createArray(); // here
    }
}


在此处标记的行将引发异常,因为您正在尝试将Object[]强制转换为String[]

如果确实需要正确的运行时类型的数组,则需要使用反射。获取所需类型的类型标记(类型为Class<T>),然后使用Array.newInstance(type, cize)创建数组,例如:

public T[] createArray(Class<T> type, int size) {
    return (T[]) Array.newInstance(type, size);
}

09-30 15:15
查看更多