在实例化时定义Arraylist的大小是否有任何优势

时间:2013-04-19 03:12:32

标签: java arrays collections arraylist

在实例化时是否有定义Arraylist大小的优势。?

如果错误或与其他可能的问题重复,请纠正我。我搜查了但是找不到我要找的东西。

定义Arraylist的初始容量是否有优势?它的默认值为10。我猜。

在调整Arraylist的大小时,如果我们在实例化时声明它会有所帮助。另外,如何潜在地克服内部调整Arraylist大小的开销。?

3 个答案:

答案 0 :(得分:5)

ArrayLists在内部使用数组,因此当ArrayList需要额外容量时,它必须在内部创建一个新数组并将元素复制到新数组。

您可以通过预先估计或查找ArrayList的确切大小来克服调整ArrayList大小的开销。或者,您可以通过处理业务逻辑确保ArrayList永远不会超出指定的大小,然后在ArrayList达到其最大所需大小时删除元素。最后,您可以使用不在内部使用数组的不同数据结构来完全避免增长问题。

答案 1 :(得分:4)

如果您知道所需的容量,提前提供它可以提高性能。否则,在添加元素时,列表实现可能需要将内部数组复制到较大的数组 - 可能重复。

答案 2 :(得分:2)

指定ArrayList的初始容量可以并且如果正确使用将提高性能。如果用得不对,可能会影响性能。

例如,如果要在循环中创建新的ArrayList实例并且知道如何计算实际最终大小或合理的起始大小,那么值得做。

但通常它不值得,甚至有害:

  • 如果分配太多“防御性”,内存使用和初始化成本可能超过默认大小的调整成本。
  • 如果代码发生变化且理想列表大小发生变化,但您忘记调整自定义初始容量,那么优化就会变得悲观。
  • 你花在像这样的微优化上的时间通常会花在其他事情上。
  • 每个附加元素的平均成本是恒定的:因为大小加倍,列表中的每个元素平均仅移动一次(在调整大小之前)或两次(在调整大小之后)。通常处理放入列表的对象的成本要高出许多倍,因此调整大小的整体影响无关紧要。

对于可索引数组是一个不错的选择的用途,ArrayList基本上和它一样好。

某些情况下

LinkedList尤其可能似乎更好,但事实并非如此!它有更大的内存开销(每个列表项额外分配!),因此即使对于它被认为有效的情况,平均性能也会更差,甚至在最终的LinkedList插入也不能保证在Java中的O(1),因为GC可能会踢在分配。它非常适合非常特殊的情况,例如一些并发算法。

有时可能进行一次优化:如果您有ArrayList盒装基元类型(如ArrayList<Integer>),请考虑使用基本类型数组(如int[])。这实际上并没有克服调整大小问题,但它避免了盒装实例的开销。但这仅适用于原始类型,而不适用于Strings

如果你可以利用一些额外的限制,你也可以创建自定义List。例如,如果您愿意增加访问时间(从直接索引访问到一次额外查找)并且只需要在末尾插入或删除,则可以创建内部{{1}的自定义List实现普通数组。因此,当您插入并填充内部数组时,您将创建一个新数组并插入其中,而不是重新分配旧数组。但由于两级结构的开销,这很少是一个整体改进,并且更实际上可以替代使用ArrayList(这也是很少正确的选择)。

所以一般情况下,如果LinkedList调整大小是有问题的,那么的最佳方法是为了获得更强大的计算机;)。另一个解决方案是改进整体算法,或者通常改善性能(因为总体性能是重要的,而不是一些小细节的孤立性能)。


有趣的是,这实际上是如何从计算的“旧时代”改变的。使用交互式应用程序,您希望某些操作在某个现实世界的时间限制内发生,因此用户体验不会受到影响。对于速度较慢的计算机,在列表大小非常小的情况下,数组列表调整大小会非常耗时。

但CPU和内存性能比典型的列表项计数提高得更快,所以像一次性调整百万元素列表的大小是没有问题的:当内存访问速度以千兆字节/秒为单位时,它只移动4/8兆字节

此外,多线程已经变得越来越普遍,非交互式线程的最坏情况响应时间并不重要,只要UI线程保持活泼,它就更多地关注整体吞吐量。因此,如果您正在处理大型数据,那么将数据处理移动到其他地方(另一个线程,一个真正的数据库)通常比尝试优化UI线程中的列表操作更好。

相关问题