在实例化时定义 Arraylist 的大小有什么好处吗?
如果有错误或与可能的其他问题重复,请纠正我。我搜索但找不到我要找的东西。
定义Arraylist的初始容量是否有好处?我猜它默认为 10。
在调整 Arraylist 的大小时,如果我们在实例化时声明会有所帮助。还有如何潜在地克服内部调整 Arraylist 大小的开销。?
在实例化时定义 Arraylist 的大小有什么好处吗?
如果有错误或与可能的其他问题重复,请纠正我。我搜索但找不到我要找的东西。
定义Arraylist的初始容量是否有好处?我猜它默认为 10。
在调整 Arraylist 的大小时,如果我们在实例化时声明会有所帮助。还有如何潜在地克服内部调整 Arraylist 大小的开销。?
ArrayList 在内部使用数组,因此当 ArrayList 需要额外容量时,它必须在内部创建一个新数组并将元素复制到新数组中。
您可以通过预先估计或找到 ArrayList 的确切大小来克服调整 ArrayList 大小的开销。或者,您可以确保 ArrayList 永远不会超过指定的大小,方法是处理您的业务逻辑,然后在 ArrayList 达到其最大所需大小时删除元素。最后,您可以使用内部不使用数组的不同数据结构来完全避免增长问题。
如果您知道所需的容量,则预先提供它可以提高性能。否则,当您添加元素时,列表实现可能需要将内部数组复制到更大的数组中——可能会重复。
为 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 线程中优化列表操作。