Java List toArray(T a)实现

我只是看着List接口中定义的方法:

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

 T[] toArray(T[] a); 

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

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

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

有没有理由说它没有这样编码?

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

  • 你需要以某种方式传入类型,并且传入指定类型的数组并不是一种不合理的方法。 不可否认,如果有一个版本,你也可以在你想要的类型中传递,速度也许会很好。
  • 如果要重用数组,可以继续传递相同的数组,而不是每次都需要创建一个新数组。 如果您需要多次执行此操作,这可以节省时间和内存以及GC问题
  357 public  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 } 

也许所以它有一个运行时类型?

来自维基:

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

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

这种方法是1.5之前Java的延续。 这是javadoc的链接

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

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

 Object[] generic_array = { "string" }; String[] strings_array = generic_array; // ClassCastException 

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

在Javagenerics之前,进行类型安全传输的唯一方法就是拥有这个cludge:

 String[] stronglyTypedArrayFromList ( List strings ) { return (String[]) strings.toArray( new String[] ); // or another variant // return (String[]) strings.toArray( new String[ strings.size( ) ] ); } 

值得庆幸的是,仿制药使这些阴谋过时了。 这个方法留在那里以提供与1.5之前的代码的向后兼容性。

我的猜测是,如果你在调用toArray(T[])已经知道了T的具体类型,那么只是声明一个数组,而不是使List实现调用Arrays.newInstance()对你而言 – 在许多情况下你可以重复使用数组。

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

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

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