java - 为什么 Collection.toArray(T[]) 不采用 E[] 代替

标签 java generics arraylist

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

class ArrayList<E> ....{
    public <T> T[] toArray(T[] a){
        if(a.length < size)
            return (T[]) Arrays.copyof(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if(a.length > size)
            a[size] = null;
        return a;
    }    
}

我想知道我们可以使用 <E>而不是 <T>在这种情况下 ?喜欢

public E[] toArray(E[] a){
      if(a.length < size)
             return (E[]) Arrays.copyof(elementData, size, a.getClass());
      System.arraycopy(elementData, 0, a, 0, size);
      if(a.length > size)
            a[size] = null;
      return a;
}    

因为 ArrayList 类本身已经是 <E> 的通用类,所以我们可以使用它来代替新的泛型类型 <T>

最佳答案

我认为John B's answer很好地涵盖了这个想法 - 我只想详细说明一下。

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

public E[] toArray(E[] a)

正如 John 所解释的,此签名不太灵活。如果我想转储 ArrayList<Integer>进入Number[] ,这个方法不让我。 Collections API 希望提供这种灵 active 。

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

根据该描述,似乎以下签名是理想的:

public <T super E> T[] toArray(T[] a)

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

嗯,这个语法:

 <T super E>

not supported by the language .但这很容易让您分心,因为这种类型检查无论如何都不起作用。问题是,与参数化类型不同,arrays are covariant .一个Integer[]Number[]是一个 Object[] .所以给定我们假设的签名 <T super E> , 如果我调用 toArrayArrayList<Number> 上并传入 Integer[] ,它仍会编译 - 并可能在运行时失败,具体取决于列表中的内容。

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

关于java - 为什么 Collection.toArray(T[]) 不采用 E[] 代替,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12355941/

相关文章:

java - 在 Swagger 中使用泛型处理特殊情况

java - 在链表末尾插入并不是一个特殊情况。那么数组的末尾呢?

java - 一次到ArrayList,还是每次到ArrayList?

java - StackOverflowError with BigInteger 用于计算 C(n,r)

java - 如何清除字符串文字池中的条目

java - 为什么 Collection 不被简单地视为 Collection<?>

c# - "where"在 C# 类声明中意味着什么?

java - 如何为我的输出添加更多值?

java - 如何在 android 中为 Picasso 使用 RoundedImageView

java - 设计模式: Object pool of connections