3

在实例化时定义 Arraylist 的大小有什么好处吗?

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

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

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

4

3 回答 3

6

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

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

于 2013-04-19T03:20:10.200 回答
4

如果您知道所需的容量,则预先提供它可以提高性能。否则,当您添加元素时,列表实现可能需要将内部数组复制到更大的数组中——可能会重复。

于 2013-04-19T03:13:57.937 回答
2

为 can 指定初始容量,ArrayList如果使用得当,将提高性能。如果使用不当,可能会损害性能。

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

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

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

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

LinkedList特别是在某些情况下可能看起来更好,但事实并非如此!它具有更大的内存开销(每个列表项的额外分配!),因此即使在它被认为是高效的情况下,平均性能也更差,甚至在 Java 中也不能保证 LinkedList 在末尾插入 O(1),因为 GC 可能会启动在分配。它仅适用于非常特殊的情况,例如一些并发算法。

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

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

所以一般来说,如果ArrayList调整大小是问题,最好的解决方法让计算机变得更强大;)。另一种解决方案是改进整体算法,或者总体上提高性能(因为整体性能很重要,而不是一些小细节的孤立性能)。


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

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

此外,多线程变得越来越普遍,非交互式线程的最坏情况响应时间并不重要,它更多的是关于整体吞吐量,只要 UI 线程保持敏捷。因此,如果您要处理这样的大数据,通常最好将数据处理移到其他地方(另一个线程,一个真实数据库),而不是尝试在 UI 线程中优化列表操作。

于 2013-04-19T03:43:20.253 回答