数组和具体化类型

Fra*_*sco 2 java arrays generics

我正在为我的 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;
   }
}
Run Code Online (Sandbox Code Playgroud)

Hoo*_*pje 5

数组是一种具体化的类型。这意味着数组的确切类型在运行时是已知的。因此,在运行时,例如String[]和之间存在差异Integer[]

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

现在,当您要创建类型参数的数组时会出现问题。在运行时不知道T是什么,所以如果你写new T[10],Java 运行时不知道要创建什么样的数组,aString[]或 a Integer[]。这就是您不能以这种方式创建数组的原因。

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

T[] theArray = (T[]) new Object[size];
Run Code Online (Sandbox Code Playgroud)

但是,您必须记住,这是非常不安全的。只有在创建的箭头的范围很小时才应该这样做,以便您可以手动确保数组只包含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
    }
}
Run Code Online (Sandbox Code Playgroud)

用此处标记的行引发异常,因为您正试图将 anObject[]转换为String[]!

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

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