Java列表toArray(T[]a)实现

Java列表toArray(T[]a)实现,java,list,generics,toarray,Java,List,Generics,Toarray,我正在查看列表界面中定义的方法: 按正确顺序返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则返回其中。否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组。 如果列表适合指定的数组,且有空闲空间(即数组中的元素多于列表),则紧跟在集合结束后的数组中的元素将设置为null。仅当调用方知道列表不包含任何空元素时,这在确定列表长度时才有用 <T> T[] toArray(T[] a); T[]toArray(T[]a); 我

我正在查看列表界面中定义的方法:

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

<T> T[] toArray(T[] a);
T[]toArray(T[]a);
我只是想知道为什么它是这样实现的,基本上如果你给它传递一个长度<的数组到list.size(),它只会创建一个新的数组并返回它。因此,在方法参数中创建新的数组对象是无用的

此外,如果您使用列表的大小将数组传递给它足够长的时间,则if返回的对象与该对象相同-实际上返回它没有意义,因为它是相同的对象,但为了清晰起见,可以

问题是,我认为这会导致代码效率稍低,我认为toArray应该只接收类并返回包含内容的新数组


没有这样编码的原因是什么?

这很可能是为了允许您重用阵列,因此您基本上可以避免(相对昂贵的)某些用例的阵列分配。另一个小得多的好处是调用方可以稍微更有效地实例化数组,因为toArray()必须使用“java.lang.reflect.array.newInstance”方法{
  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       }
358如果(a.长度<尺寸) 359//创建a的运行时类型的新数组,但我的内容: 360 return(T[])array.copyOf(elementData,size,a.getClass()); 361系统阵列副本(elementData,0,a,0,大小); 362如果(a.长度>尺寸) 363 a[尺寸]=零; 364返回a; 365 } 也许它有一个运行时类型

从维基:

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


正如其他人提到的,有两个不同的原因:

  • 您需要以某种方式传入类型,传入指定类型的数组并不是一种不合理的方式。诚然,为了提高速度,如果在类中也传递了您想要的类型的版本,这可能会很好
  • 如果要重用阵列,可以继续传递相同的阵列,而无需每次都创建一个新阵列。这可以节省时间和内存,如果需要多次执行,还可以解决GC问题

此方法是对1.5 Java之前版本的保留。这里是链接到

当时,这是将列表转换为可重新定义数组的唯一方法

这是一个模糊的事实,但尽管可以在Object[]数组中存储任何内容,但不能将此数组强制转换为更具体的类型,例如

Object[] generic_array = { "string" };

String[] strings_array = generic_array; // ClassCastException
看起来效率更高的
List.toArray()
就是这样做的,它创建了一个通用的
对象
数组

在Java泛型之前,执行类型安全传输的唯一方法是使用以下clude:

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
的具体类型,只声明一个数组比为您调用
列表
实现
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);
}
publicstatice[]ToArray(集合c,类componentType){
E[]数组=(E[])array.newInstance(componentType,c.size());
返回c.toArray(数组);
}

(请注意,无法将
E[]写入数组(集合c)
,因为没有
Class
对象,无法在运行时创建
E
数组,也无法在运行时为
E
获取
Class
对象,因为泛型已被删除。)

您认为效率低下的具体原因是什么?如果您向它传递一个大小为私有静态final T[]=new T[0]
并在数组大小未知时使用它,仍然没有理由不只是传递一个类参数并使用它来代替.getClass()。但是如果有人传递一个数组