Java List toArray(T [] a)实现

时间:2011-06-30 23:41:56

标签: java list generics toarray

我只是在查看List界面中定义的方法:

  

以正确的顺序返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则返回其中。否则,将使用指定数组的运行时类型和此列表的大小分配新数组。   如果列表适合指定的数组,并且有空余空间(即,数组的元素多于列表),则紧跟集合结尾的数组中的元素将设置为null。仅当调用者知道列表不包含任何null元素时,这在确定列表长度时很有用。

<T> T[] toArray(T[] a);

我只是想知道为什么它以这种方式实现,基本上如果你传递一个长度为&lt;的数组。到list.size(),它只会创建一个新的并返回它。因此,在方法参数中创建新的Array对象是没用的。

此外,如果你使用列表的大小传递一个足够长的数组,如果返回与对象相同的对象 - 返回它真的没有意义,因为它是同一个对象但是为了清晰起见。

问题在于我认为这会促使代码效率稍低,在我看来,Array应该只是接收类并只返回带有内容的新数组。

有没有什么理由不以这种方式编码?。

5 个答案:

答案 0 :(得分:6)

  357       public <T> T[] toArray(T[] a) {
  358           if (a.length < size)
  359               // Make a new array of a's runtime type, but my contents:
  360               return (T[]) Arrays.copyOf(elementData, size, a.getClass());
  361           System.arraycopy(elementData, 0, a, 0, size);
  362           if (a.length > size)
  363               a[size] = null;
  364           return a;
  365       }

也许它有运行时类型?

来自wiki:

  

因此,实例化Java   参数化类的类是   不可能因为实例化   需要调用构造函数,   如果类型是不可用的   未知的。

答案 1 :(得分:5)

正如其他人所说,有几个不同的原因:

  • 你需要以某种方式传入类型,传入指定类型的数组并不是一种不合理的方法。不可否认,如果您为了速度而在类型的Class中传递了一个版本,那可能会很好。
  • 如果要重用数组,可以继续传递相同的数组,而不是每次都需要创建一个新数组。这可以节省时间和内存,并且如果您需要多次执行此操作,则会出现GC问题

答案 2 :(得分:3)

最有可能的是允许您重用数组,因此您基本上避免(相对昂贵的)某些用例的数组分配。另一个小得多的好处是调用者可以稍微更有效地实例化数组,因为toArray()必须使用'java.lang.reflect.Array.newInstance'方法。

答案 3 :(得分:2)

此方法是1.5之前版本的保留。以下是javadoc

的链接

当时那是将列表转换为可再生数组的唯一方法。

这是一个模糊的事实,但是虽然您可以在Object []数组中存储任何内容,但您无法将此数组转换为更具体的类型,例如。

Object[] generic_array = { "string" };

String[] strings_array = generic_array; // ClassCastException

看起来效率更高List.toArray()就是这样,它会创建一个通用的Object数组。

在Java泛型之前,进行类型安全转移的唯一方法就是拥有这个cludge:

String[] stronglyTypedArrayFromList ( List strings )
{
    return (String[]) strings.toArray( new String[] );
    // or another variant
    // return (String[]) strings.toArray( new String[ strings.size( ) ] );
}
谢天谢地,仿制药让这些阴谋过时了。留下这个方法是为了提供与1.5之前代码的向后兼容性。

答案 4 :(得分:2)

我的猜测是,如果你在调用T时已经知道toArray(T[])的具体类型,那么只需声明一个数组而不是List就更高效了。为您实现调用Arrays.newInstance() - 在许多情况下,您可以重新使用该数组。

但如果它让你烦恼,那么编写一个实用方法就很容易了:

public static <E> E[] ToArray(Collection<E> c, Class<E> componentType) {
    E[] array = (E[]) Array.newInstance(componentType, c.size());
    return c.toArray(array);
}

(注意,没有办法编写<E> E[] ToArray(Collection<E> c),因为在没有E对象的情况下,无法在运行时创建Class数组,也无法获得Class 1}}运行时E的对象,因为泛型已被删除。)