为什么Collection.toArray(T )不采用E

toArray方法(让我们在java.util.ArrayList选择实现)如下:

 class ArrayList ....{ public  T[] toArray(T[] a){ if(a.length  size) a[size] = null; return a; } } 

我想知道在这种情况下我们可以使用代替吗? 喜欢

 public E[] toArray(E[] a){ if(a.length  size) a[size] = null; return a; } 

由于ArrayList类iteself已经是通用,所以我们可以使用它而不是新的generics类型吗?

的要点是,如果所需的数组是E的基类。 例如,如果EHashMap但所需的数组是Map[] 。 如果将toArray锁定到E这是不可能的。

由于类型擦除,通用集合/类型中不需要这种类型的东西。 但是arrays没有类型擦除,因此arrays的类型非常重要。

我认为John B的答案很好地涵盖了这个想法 – 我只想详细说明一下。

首先,让我们看一下您在问题中提出的方法签名:

 public E[] toArray(E[] a) 

正如约翰所解释的那样,这种签名不够灵活。 如果我想将ArrayList转储到Number[] ,这个方法不允许我。 Collections API希望允许这种灵活性。

不幸的是,现有的方法不允许对数组类型进行编译时检查,这是您似乎遇到的问题。 由Collection声明的toArray文档解释说,如果指定数组的运行时类型不是此集合中每个元素的运行时类型的超类型,则可能抛出ArrayStoreException

基于该描述, 似乎以下签名是理想的:

 public  T[] toArray(T[] a) 

乍一看,这似乎允许传入和填充任何合法类型的数组 – 但是会在编译时而不是运行时提供类型检查。 那么为什么这个签名没有被声明呢?

好吧,这个语法:

   

语言不支持 。 但是这很容易让你分心这种类型检查无论如何都不会起作用的事实。 问题是,与参数化类型不同, 数组是协变的 。 Integer[]Number[]Object[] 。 因此,假设我用假设签名,如果我在ArrayList上调用toArray并传入Integer[] ,它仍然会编译 – 并且可能在运行时失败,具体取决于列表中的内容。

所以底线是,传入的数组的组件类型的下限不会有任何好处。