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)
数组是一种具体化的类型。这意味着数组的确切类型在运行时是已知的。因此,在运行时,例如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)