数组和具体类型

时间:2015-10-26 20:01:22

标签: java arrays generics

我正在为我的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;
   }
}

3 个答案:

答案 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>,但确实有效:)