Java List toArray(T[] a) 实现

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6542242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:17:03  来源:igfitidea点击:

Java List toArray(T[] a) implementation

javalistgenericstoarray

提问by Oscar Gomez

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

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

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);

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

<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.

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

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.

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

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

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

采纳答案by RHSeeger

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
  • 您需要以某种方式传入类型,并且传入指定类型的数组并不是一种不合理的方式。诚然,如果有一个版本可以传递给您想要的类型的类,以提高速度,那可能会很好。
  • 如果你想重用你的数组,你可以不断传入同一个数组,而不是每次都创建一个新数组。这可以节省时间和内存,并且如果您需要多次执行 GC 问题

回答by dfb

  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.

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

回答by StaxMan

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.

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

回答by Alexander Pogrebnyak

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

此方法是 Java 1.5 之前的保留版本。这是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[] 数组中存储任何内容,但您不能将此数组转换为更具体的类型,例如

Object[] generic_array = { "string" };

String[] strings_array = generic_array; // ClassCastException

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

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

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

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

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.

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

回答by David Moles

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

我的猜测是,如果您已经知道T您正在调用的具体类型toArray(T[]),那么只声明一个数组比为您进行List实现调用更Arrays.newInstance()高效——而且在许多情况下您可以重用数组。

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 Eat runtime without a Classobject, and no way to get a Classobject for Eat runtime, because the generics have been erased.)

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