我经常使用ArrayList
而不是“普通”的array[]
。
当我使用ArrayList
时,我感到好像在作弊(或懒惰),那么什么情况下可以使用ArrayList
替换数组?
数组是强类型的,并且作为参数很有效。如果您知道您的集合长度固定,应该使用数组。
ArrayList 不是强类型的,每次插入或检索都需要转换回原始类型。如果您需要一个方法来获取特定类型的列表,ArrayList 将会有所不足,因为您可以传递包含任何类型的 ArrayList。ArrayList 在内部使用动态扩展数组,因此当其达到容量时,还需要扩展内部数组的大小。
您真正想使用的是一个泛型列表,比如 List<T>
。它具有数组和 ArrayList 的所有优点。它是强类型的,并支持可变长度的项目。
除了Bob和Frederick的回答,我想指出的是,虽然数组具有协变性,但泛型列表没有。例如,类型为MyChildClass[]
的数组可以轻松地转换为MyParentClass[]
,而List<MyChildClass>
不能直接转换为List<MyParentClass>
。
如果你需要协变性,可以使用数组、使用LINQ的Cast()方法或其他方式逐个转换每个项或等待C# 4。
T[]
) 是完全可变的,无法受到保护。 List<T>
没有提供任何有用的扩展点,但像 Collection<T>
(或许多其他 IList<T>
实现) 这样的东西允许您添加代码,例如在添加项目之前检查它们;同样,您可以拥有只读的 IList<T>
实现,在需要不可变性的线程安全性方面非常有用。params
参数,或者在我知道项目长度并且我知道代码选择不对其进行变异(作为私有字段)的一些高度优化的情况下使用它们。除此之外,List<T>
等更常见,因为在添加/删除项目时它们具有更少的开销。ArrayList
,都应该使用 List<T>
泛型集合。它比前者更加强类型化。我从Java的角度回答这个问题,但基本问题是相同的。使用更高级的抽象不应该让你感到内疚。毕竟,你使用的是String
而不是char[]
或者byte[]
?我甚至建议在可能的情况下再往前走一步,使用List
接口。唯一需要降低一步的原因是出于性能考虑。
使用更高级的集合抽象有很多优点。你可以添加装饰器使List只读、固定大小、检查进入或离开集合的项目或使用视图(参见C#中的GetRange
和Java中的subList
)。
顺便说一句,ArrayList
应该总是基于一个原始数组,否则名称就是错误的。操作通常实现得就像你使用原始数组时所期望的那样。如果使用了链表,通常会命名为LinkedList
。这也是使用接口的优点之一:您可以随后更改所使用的实现。
使用集合的一些问题使得它们变得笨重。其中一个警告是,集合通常基于对象,并且语言在原始类型和对象类型之间存在相当大的差距。有限的泛型也没有太大帮助。尽管如此,除非有充分的理由,否则我建议使用集合而不是数组。
对于原始值,您还可以考虑使用原始集合库,例如GNU Trove。不知道C#是否有类似的东西。
首先,如果您只打算处理特定类型,那么不应该使用ArrayList。例如,如果您只期望一个字节数组,则应该仅接受一个字节数组。
我认为唯一需要考虑使用ArrayList的情况是代替List。