我们知道,List与数组的区别是,可以Add元素,但是这是如何实现的呢?
翻看源码,解开面纱,发现List的内部实现,就是使用数组实现的。
List的源码地址:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,cf7f4095e4de7646
部分源码片段解答:
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T> { private const int _defaultCapacity = 4; private T[] _items; [ContractPublicPropertyName("Count")] private int _size; private int _version; [NonSerialized] private Object _syncRoot; static readonly T[] _emptyArray = new T[0]; }
其中,_items
变量中便是存储的List中的元素
_size
就是List中的元素个数
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,52
// Constructs a List. The list is initially empty and has a capacity // of zero. Upon adding the first element to the list the capacity is // increased to 16, and then increased in multiples of two as required. public List() { _items = _emptyArray; }
这时候,_items
变量为长度为0的数组
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,60
// Constructs a List with a given initial capacity. The list is // initially empty, but will have room for the given number of elements // before any reallocations are required. // public List(int capacity) { if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); Contract.EndContractBlock(); if (capacity == 0) _items = _emptyArray; else _items = new T[capacity]; }
如果传入的容量是0,则_items
为长度为0的数组,否则,为capacity
大小的数组(无任何元素)
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,74
// Constructs a List, copying the contents of the given collection. The // size and capacity of the new list will both be equal to the size of the // given collection. // public List(IEnumerable<T> collection) { if (collection==null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); Contract.EndContractBlock(); ICollection<T> c = collection as ICollection<T>; if( c != null) { int count = c.Count; if (count == 0) { _items = _emptyArray; } else { _items = new T[count]; c.CopyTo(_items, 0); _size = count; } } else { _size = 0; _items = _emptyArray; // This enumerable could be empty. Let Add allocate a new array, if needed. // Note it will also go to _defaultCapacity first, not 1, then 2, etc. using(IEnumerator<T> en = collection.GetEnumerator()) { while(en.MoveNext()) { Add(en.Current); } } } }
如果传入的集合为空,则抛出异常
如果传入的集合长度为0,则_items
为长度为0的数组
如果集合有内容,则把集合的内容添加到_items
中,这时,_size=items.Lenth
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,220
// Adds the given object to the end of this list. The size of the list is // increased by one. If required, the capacity of the list is doubled // before adding the new element. // public void Add(T item) { if (_size == _items.Length) EnsureCapacity(_size + 1); _items[_size++] = item; _version++; }
从注释可以看到:
_items
的容量会增大一倍_size
会+1其中_items
的容量增大一倍,在EnsureCapacity
函数中实现:
https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,405
// Ensures that the capacity of this list is at least the given minimum // value. If the currect capacity of the list is less than min, the // capacity is increased to twice the current capacity or to min, // whichever is larger. private void EnsureCapacity(int min) { if (_items.Length < min) { int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2; // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow. // Note that this check works even when _items.Length overflowed thanks to the (uint) cast if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength; if (newCapacity < min) newCapacity = min; Capacity = newCapacity; } }
可以看到
_items
的长度为0,则扩容时,长度为_defaultCapacity
也就是4_items
的长度不为0,则扩容时,长度为_items.Lenth*2
Capacity = newCapacity
,跳转到Capacity的set中:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,110
// Gets and sets the capacity of this list. The capacity is the size of // the internal array used to hold items. When set, the internal // array of the list is reallocated to the given capacity. // public int Capacity { get { Contract.Ensures(Contract.Result<int>() >= 0); return _items.Length; } set { if (value < _size) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity); } Contract.EndContractBlock(); if (value != _items.Length) { if (value > 0) { T[] newItems = new T[value]; if (_size > 0) { Array.Copy(_items, 0, newItems, 0, _size); } _items = newItems; } else { _items = _emptyArray; } } } }
扩容时,New了一个新的数组,长度为Capacity,将_items
之前的元素(如果有)复制到新的数组。然后将新的数组赋值到_items