列表容量返回的项目多于添加的项目
List
上有几个属性似乎与列表中的项目数相关 – Capacity
, Count
(作为属性和方法存在)。 与仅具有Length
Array
相比,这非常令人困惑。
我正在使用List.Capacity
但它会产生意想不到的结果:
List fruits = new List(); fruits.Add("apple"); fruits.Add("orange"); fruits.Add("banana"); fruits.Add("cherry"); fruits.Add("mango"); Console.WriteLine("the List has {0} items in it.", fruits.Capacity);
当我运行它时,控制台显示:
列表中有4个项目。
我不明白为什么它显示8的Capacity
,当我只添加5项。
列表的Capacity
表示列表当前为要添加到其中的当前对象和对象留出的内存量。 列表的Count
是实际添加到列表中的项目数。
以下是MSDN中 Capacity属性的完整说明:
容量是List
在需要resize之前可以存储的元素数,而Count是实际位于List
的元素数。
容量始终大于或等于Count。 如果Count在添加元素时超出容量,则在复制旧元素和添加新元素之前,通过自动重新分配内部数组来增加容量。
可以通过调用TrimExcess()方法或显式设置Capacity属性来减少容量。 当显式设置Capacity的值时,还会重新分配内部数组以容纳指定的容量,并复制所有元素。
检索此属性的值是O(1)操作; 设置属性是O(n)操作,其中n是新容量。
要添加到其他答案,List逐个添加项时的默认行为是以容量4开始,并在列表变满时将其加倍。 这解释了8的容量。
为了理解它为什么更大,您需要了解List
如何在内部工作。 在内部, List
使用数组(所以T[]
)来存储其内容。
这个数组以4个元素的大小开始,相当于说T[] array = new T[4]
。 当您将项目添加到List
,它将存储在数组中: array[0]
的第一项, array[1]
的第二项等。但是,第五项不适合此数组,因为它只有四个元素长。 并且因为在创建数组之后无法更改数组的长度,所以唯一的选择是获取数组的内容并将其移动到一个足以容纳第五个项目的新数组。 List
的实现选择在每次空间用完时将数组缓冲区的大小加倍,因此为了适应第五项,它将数组容量加倍为8.然后是16,依此类推。
对于它为什么选择加倍可能有很好的数学支持,它可能是昂贵的复制操作(不想经常分配新缓冲区)和浪费空间之间的良好折衷。 通过加倍,内存浪费永远不会超过50%,并且新arrays需要分配的次数会以对数方式减少,我相信。
容量与列表的项目计数不同。 默认情况下,所有语言中实现良好的列表容器分配的内存超过了保存当前条目数所需的内存。 这是因为在某些时候分配更大的内存块比在每次添加内存时为另外一个项目分配内存更有效。