【问题标题】:Why is there no toArray(Class<T>)?为什么没有 toArray(Class<T>)?
【发布时间】:2019-12-09 07:21:29
【问题描述】:

为什么List中没有toArray变种只接受一个类型,例如:

Foo[] array = list.toArray(Foo.class);
// or
Foo[] array = list.toArray(Foo[].class);

见过

// existing array
Foo[] array = list.toArray(array);
// Fake array
Foo[] array = list.toArray(new Foo[0]);

但是当我只想指定类型而不创建不必要的一次性数组时,创建一个空数组似乎效率低下且违反直觉。

【问题讨论】:

  • 不清楚你在问什么。您可以将现有数组传递给toArray,如果列表适合它,则将使用它。 (如果没有,则创建一个新的。)所以...?
  • 无论您传入Type[].class 还是new Type[0],都需要以任一方式实例化一个新对象。前者需要反思。
  • @VinceEmigh 因为toArray 无论如何都会为你创建一个新数组,如果给定数组太小,它已经使用反射,当你传入@987654330 @,您实际上是在创建 2 数组,因为零长度数组将被丢弃,因此传入 Type[].class 实际上会更有效。
  • @Andreas 我没有提到哪个更有效,我只是说明任何一种方式都会导致新实例,以消除关于“可能会不必要地使用 ctor 的任何误解”。是的,通过传入一个大小太小的数组,Array.newInstance 将被调用(基于我看到的最后一个实现)。

标签: java arrays collections toarray


【解决方案1】:

从界面的角度来看,我同意。

方法只需要类型(除了副作用),所以只需要类型是合适的。

我猜主要原因是效率。仅采用类型的实现要慢得多,但我没有检查实现细节(请参阅.toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])? 中的基准和博客Arrays of Wisdom of the Ancients)。

但是,请注意,我们从 Java 11 开始有了一个新变体,它更接近您想要的,并且在这种情况下也更合适:

toArray(Foo[]::new)

来自其documentation

返回一个包含此集合中所有元素的数组,使用提供的生成器函数分配返回的数组。

使用toArray() 创建运行时类型为Object[] 的数组,或使用toArray(T[]) 重用现有数组。

默认实现用零调用生成器函数,然后将结果数组传递给toArray(T[])

该方法不需要反射,因为您直接提供生成器。

总而言之,现在你应该使用

  • toArray() 如果你想要 Object[](很少合适),
  • toArray(T[])如果你想重用现有的数组(应该足够大),
  • toArray(IntFunction&lt;T[]&gt;) 如果您想要类型安全和新数组。

【讨论】:

  • “只接受类型的实现明显慢,因为它需要使用反射来动态创建数组”。当您传入一个零长度数组并且toArray 必须重新调整它的大小时,这正是发生的情况,而且似乎很多人传入零长度数组,因为他们懒得调用size() 方法有问题的集合。 --- 不过,请给我投票。
  • @Andreas Iirc 这里有人对其进行了基准测试,传入0 长度数组比传入正确大小的数组要快得多。
  • 长话短说,HotSpot 具有创建新数组的内在特性,因此可以提高性能。来自链接的帖子:reflective intrinsics
  • @Andreas 传递零比传递实际大小快;如果 VM 可以证明指定数组中的分配将随之而来,则它不必对数组进行归零;事实证明这更快。
猜你喜欢
  • 1970-01-01
  • 2019-07-30
  • 2010-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
相关资源
最近更新 更多