我正在为我的Java期中考试,但我对这个类型有一些问题。这里有一个错误的类,但我不明白为什么。有人可以帮助我,也许可以给我一些解释吗?当然,错误与具体类型有关。
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;
}
}
答案 0 :(得分:4)
数组是一种具体类型。这意味着在运行时已知数组的确切类型。因此,在运行时,例如String[]
和Integer[]
之间存在差异。
泛型不是这种情况。泛型是一个编译时构造:它们用于在编译时检查类型,但在运行时,确切的类型不再可用。在运行时,类型参数只是Object
(或者如果类型参数具有上限,则其上限)。因此,在运行时,Collection<String>
和Collection<Integer>
的类型没有区别。
现在,当您想要创建类型参数的数组时,会出现问题。在运行时,不知道T
是什么,所以如果你写new T[10]
,Java运行时不知道要创建什么类型的数组,String[]
或{{1 }}。这就是为什么你不能以这种方式创建一个数组。
有一些解决方法,其中没有一个是完全令人满意的。通常的解决方案是创建一个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)
答案 1 :(得分:3)
Reifiable type由JLS定义为:
当且仅当下列之一成立时,类型才可以恢复:
- 它指的是非泛型类或接口类型声明。
- 这是一个参数化类型,其中所有类型参数都是无界通配符(§4.5.1)。
- 这是一种原始类型(§4.8)。
- 这是一种原始类型(§4.2)。
- 它是一种数组类型(第10.1节),其元素类型是可以恢复的。
- 这是一种嵌套类型,对于每个以“。”分隔的T类型,T本身都是可以恢复的。
另见§4.7后面的注释,详细描述了推理。
您的类型参数不是上述参数,因此无法恢复。因此不能在array creation expression中使用:
如果ClassOrInterfaceType不表示,则为编译时错误 可再生类型(§4.7)。否则,ClassOrInterfaceType可能会命名 任何命名的引用类型,甚至是抽象类类型(第8.1.1.1节)或 界面类型。
答案 2 :(得分:2)
您无法创建泛型类型的数组。编译器可能会抱怨像“通用数组创建”这样的东西。围绕这个没有好办法,但有办法做到这一点:
public static <T> T[] toArray(Class<T> type, Collection<T> c) {
T[] a = (T[]) Array.newInstance(type, c.size())
…
}
你需要Class<T>
,但确实有效:)