Java List toArray(T[] a) 实现

发布于 2024-11-17 21:23:00 字数 571 浏览 4 评论 0原文

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

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

<前><代码>; T[] toArray(T[] a);

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

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

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

有什么原因不这样编码吗?

I was just looking at the method defined in the List interface:

Returns an array containing all of the elements in this list in the correct order; the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the collection is set to null. This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.

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

And I was just wondering why is it implemented this way, basically if you pass it an array with a length < to the list.size(), it will simply create a new one and return it. Therefore the creation of the new Array Object in the method parameter is useless.

Additionally if you pass it an array long enough using the size of the list if returns that same object with the objects - really no point in returning it since it is the same object but ok for clarity.

The problem is that I think this promotes slightly inefficient code, in my opinion toArray should simply receive the class and just return the new array with the contents.

Is there any reason why it is not coded that way?.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

箹锭⒈辈孓 2024-11-24 21:23:00
  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
参数化类型的类是
不可能,因为实例化
需要调用构造函数,
如果类型是,则不可用
未知。

  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       }

Maybe so it has a runtime type?

From wiki:

Consequently, instantiating a Java
class of a parameterized type is
impossible because instantiation
requires a call to a constructor,
which is unavailable if the type is
unknown.

海拔太高太耀眼 2024-11-24 21:23:00

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

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

As mentioned by others, there are a couple different reasons:

  • You need to pass in the type somehow, and passing in an array of the specified type isn't an unreasonable way to do it. Admittedly, it might be nice if there was a version that you pass in the Class of the type you want too, for speed.
  • If you want to reuse your array, you can keep passing in the same one, rather than needing to create a new one each time. This can save time and memory, and GC issues if you need to do it many, many times
↘人皮目录ツ 2024-11-24 21:23:00

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

Most likely this is to allow you to reuse arrays, so you basically avoid (relatively costly) array allocation for some use cases. Another much smaller benefit is that caller can instantiate array slightly more efficiently, since toArray() must use 'java.lang.reflect.Array.newInstance' method.

红墙和绿瓦 2024-11-24 21:23:00

此方法是 1.5 之前的 Java 的延续。这是 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 之前的代码的向后兼容性。

This method is a holdover from pre-1.5 Java. Here is the link to javadoc

Back then it was the only way to convert a list to a reifiable array.

It is an obscure fact, but although you can store anything in the Object[] array, you cannot cast this array to more specific type, e.g.

Object[] generic_array = { "string" };

String[] strings_array = generic_array; // ClassCastException

Seemingly more efficient List.toArray() does just that, it creates a generic Object array.

Before Java generics, the only way to do a type-safe transfer was to have this cludge:

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

Thankfully generics made these kind of machinations obsolete. This method was left there to provide backward compatibility with pre 1.5 code.

中二柚 2024-11-24 21:23:00

我的猜测是,如果您在调用 toArray(T[]) 时已经知道 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[] ToArray(Collectionc),因为没有办法在运行时创建一个没有 Class 对象的 E 数组,并且无法获取 EClass 对象> 在运行时,因为泛型已被删除。)

My guess is that if you already know the concrete type of T at the point you're calling toArray(T[]), it's more performant to just declare an array of whatever it is than make the List implementation call Arrays.newInstance() for you -- plus in many cases you can re-use the array.

But if it annoys you, it's easy enough to write a utility method:

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

(Note that there's no way to write <E> E[] ToArray(Collection<E> c), because there's no way to create an array of E at runtime without a Class object, and no way to get a Class object for E at runtime, because the generics have been erased.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文