12

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

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

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

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

此外,如果您使用列表的大小向它传递一个足够长的数组,如果返回与对象相同的对象 - 实际上返回它没有意义,因为它是相同的对象,但为了清楚起见可以。

问题是我认为这会导致代码效率低下,我认为 toArray 应该简单地接收类并返回带有内容的新数组。

有什么理由不这样编码吗?

4

5 回答 5

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       }

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

来自维基:

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

于 2011-06-30T23:55:19.513 回答
5

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

  • 您需要以某种方式传入类型,并且传入指定类型的数组并不是一种不合理的方式。诚然,如果有一个版本可以在您想要的类型的 Class 中传递,这可能会很好,以提高速度。
  • 如果你想重用你的数组,你可以一直传入同一个数组,而不是每次都需要创建一个新数组。这可以节省时间和内存,如果你需要做很多次,GC 问题
于 2011-07-01T00:12:17.940 回答
3

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

于 2011-06-30T23:49:08.753 回答
2

此方法是 Java 1.5 之前的保留方法。这是javadoc的链接

当时,这是将列表转换为可具体化数组的唯一方法。

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

Object[] generic_array = { "string" };

String[] strings_array = generic_array; // ClassCastException

这样做似乎更有效List.toArray(),它创建了一个通用Object数组。

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

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

值得庆幸的是,仿制药使这种诡计过时了。保留此方法是为了提供与 1.5 之前的代码的向后兼容性。

于 2011-07-01T00:20:34.677 回答
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)创建数组,也无法在运行时获取对象,因为泛型已被删除。)EClassClassE

于 2011-07-01T00:38:29.497 回答