ArrayList的源码和List的源码基本相似,只不过List是泛型集合而ArrayList是Object,关于ArrayList和List的优缺点这里不再叙述,请自行百度。需要说明的一点List实现了IList
private Object[] _items; //内部数组
[ContractPublicPropertyName("Count")]
private int _size; //存储的元素数量
private int _version; //版本号
[NonSerialized]
private Object _syncRoot; //Lock锁相关
private const int _defaultCapacity = 4; //默认容量
private static readonly Object[] emptyArray = EmptyArray
其中的emptyArray和List的稍微有些不同,指向了EmptyArray
// Useful in number of places that return an empty byte array to avoid unnecessary memory allocation.
internal static class EmptyArray
{
public static readonly T[] Value = new T[0];
}
// Note: this constructor is a bogus constructor that does nothing
// and is for use only with SyncArrayList.
internal ArrayList( bool trash )
{
}
// Constructs a ArrayList. The list is initially empty and has a capacity
// of zero. Upon adding the first element to the list the capacity is
// increased to _defaultCapacity, and then increased in multiples of two as required.
#if !FEATURE_CORECLR
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
public ArrayList() {
_items = emptyArray;
}
// Constructs a ArrayList 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 ArrayList(int capacity) {
//容量不能小于0
if (capacity < 0) throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "capacity"));
Contract.EndContractBlock();
//给定的容量为0则指向空数组,否则new新数组
if (capacity == 0)
_items = emptyArray;
else
_items = new Object[capacity];
}
// Constructs a ArrayList, 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 ArrayList(ICollection c) {
if (c==null)
throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection"));
Contract.EndContractBlock();
int count = c.Count;
if (count == 0)
{
_items = emptyArray;
}
else {
_items = new Object[count];
AddRange(c);
}
}
// 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 virtual int Capacity {
get {
Contract.Ensures(Contract.Result() >= Count);
return _items.Length;
}
set {
//若设置的容量小于当前数量
if (value < _size) {
throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
}
Contract.Ensures(Capacity >= 0);
Contract.EndContractBlock();
// We don't want to update the version number when we change the capacity.
// Some existing applications have dependency on this.
//设置的容量不等于内部数组大小时才扩容
if (value != _items.Length) {
//设置的容量只能大于等于存储的元素数量且不能等于内部数组的大小,其取值范围为[_size,_items.Length)和(_items.Length,∞]
//_size的取值范围[0,_items.Length]
if (value > 0) {
Object[] newItems = new Object[value];
if (_size > 0) {
Array.Copy(_items, 0, newItems, 0, _size);
}
_items = newItems;
}
else {
_items = new Object[_defaultCapacity];
}
}
}
}
// 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) {
//除第一次扩容外,其他扩容时会扩容为原来的2倍
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
//可以看到List的大小是有极限的
if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
//判断计算出的容量是否使用
if (newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
}
// Sets the capacity of this list to the size of the list. This method can
// be used to minimize a list's memory overhead once it is known that no
// new elements will be added to the list. To completely clear a list and
// release all memory referenced by the list, execute the following
// statements:
//
// list.Clear();
// list.TrimToSize();
//
public virtual void TrimToSize() {
Capacity = _size;
}
和List一样的实现。
// 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 virtual int Add(Object value) {
Contract.Ensures(Contract.Result() >= 0);
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size] = value;
_version++;
return _size++;
}
// Clones this ArrayList, doing a shallow copy. (A copy is made of all
// Object references in the ArrayList, but the Objects pointed to
// are not cloned).
public virtual Object Clone()
{
Contract.Ensures(Contract.Result
Clone是实现ICloneable的函数,函数内部通过new出一个新的ArrayList,同时把所有的数据复制了一份,并更新了存储的元素数量和版本号。
// Clears the contents of ArrayList.
public virtual void Clear() {
if (_size > 0)
{
Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
_size = 0;
}
_version++;
}
如果存储的元素数量大于0,调用Array.Clear()清空数据,同时归零_size。
// Contains returns true if the specified element is in the ArrayList.
// It does a linear, O(n) search. Equality is determined by calling
// item.Equals().
//
public virtual bool Contains(Object item) {
if (item==null) {
for(int i=0; i<_size; i++)
if (_items[i]==null)
return true;
return false;
}
else {
for(int i=0; i<_size; i++)
if ( (_items[i] != null) && (_items[i].Equals(item)) )
return true;
return false;
}
}
Contains函数和List的实现一样,通过for循环判断,同样会判断null,说明ArraList同样可以存入null。
// Copies this ArrayList into array, which must be of a
// compatible array type.
//
public virtual void CopyTo(Array array) {
CopyTo(array, 0);
}
// Copies this ArrayList into array, which must be of a
// compatible array type.
//
public virtual void CopyTo(Array array, int arrayIndex) {
if ((array != null) && (array.Rank != 1))
throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
Contract.EndContractBlock();
// Delegate rest of error checking to Array.Copy.
Array.Copy(_items, 0, array, arrayIndex, _size);
}
// Copies a section of this list to the given array at the given index.
//
// The method uses the Array.Copy method to copy the elements.
//
public virtual void CopyTo(int index, Array array, int arrayIndex, int count) {
if (_size - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if ((array != null) && (array.Rank != 1))
throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
Contract.EndContractBlock();
// Delegate rest of error checking to Array.Copy.
Array.Copy(_items, index, array, arrayIndex, count);
}
和Listyi一样最后调用Array.Copy函数进行实现。
// Returns the index of the first occurrence of a given value in a range of
// this list. The list is searched forwards from beginning to end.
// The elements of the list are compared to the given value using the
// Object.Equals method.
//
// This method uses the Array.IndexOf method to perform the
// search.
//
#if !FEATURE_CORECLR
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
public virtual int IndexOf(Object value) {
Contract.Ensures(Contract.Result() < Count);
return Array.IndexOf((Array)_items, value, 0, _size);
}
// Returns the index of the first occurrence of a given value in a range of
// this list. The list is searched forwards, starting at index
// startIndex and ending at count number of elements. The
// elements of the list are compared to the given value using the
// Object.Equals method.
//
// This method uses the Array.IndexOf method to perform the
// search.
//
public virtual int IndexOf(Object value, int startIndex) {
if (startIndex > _size)
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
Contract.Ensures(Contract.Result() < Count);
Contract.EndContractBlock();
return Array.IndexOf((Array)_items, value, startIndex, _size - startIndex);
}
// Returns the index of the first occurrence of a given value in a range of
// this list. The list is searched forwards, starting at index
// startIndex and upto count number of elements. The
// elements of the list are compared to the given value using the
// Object.Equals method.
//
// This method uses the Array.IndexOf method to perform the
// search.
//
public virtual int IndexOf(Object value, int startIndex, int count) {
if (startIndex > _size)
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (count <0 || startIndex > _size - count) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
Contract.Ensures(Contract.Result() < Count);
Contract.EndContractBlock();
return Array.IndexOf((Array)_items, value, startIndex, count);
}
最终调用Array.IndexOf函数,其函数实现如下:
// Returns the index of the first occurrence of a given value in a range of
// an array. The array is searched forwards, starting at index
// startIndex and upto count elements. The
// elements of the array are compared to the given value using the
// Object.Equals method.
//
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int IndexOf(Array array, Object value, int startIndex, int count) {
if (array==null)
throw new ArgumentNullException("array");
if (array.Rank != 1)
throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
Contract.Ensures(Contract.Result() < array.GetLowerBound(0) + array.Length);
Contract.EndContractBlock();
int lb = array.GetLowerBound(0);
if (startIndex < lb || startIndex > array.Length + lb)
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (count < 0 || count > array.Length - startIndex + lb)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
// Try calling a quick native method to handle primitive types.
int retVal;
bool r = TrySZIndexOf(array, startIndex, count, value, out retVal);
if (r)
return retVal;
Object[] objArray = array as Object[];
int endIndex = startIndex + count;
if (objArray != null) {
if (value == null) {
for (int i = startIndex; i < endIndex; i++) {
if (objArray[i] == null) return i;
}
}
else {
for (int i = startIndex; i < endIndex; i++) {
Object obj = objArray[i];
if (obj != null && obj.Equals(value)) return i;
}
}
}
else {
for (int i = startIndex; i < endIndex; i++) {
Object obj = array.GetValue(i);
if( obj == null) {
if(value == null) return i;
}
else {
if( obj.Equals(value)) return i;
}
}
}
// Return one less than the lower bound of the array. This way,
// for arrays with a lower bound of -1 we will not return -1 when the
// item was not found. And for SZArrays (the vast majority), -1 still
// works for them.
return lb-1;
}
Array.IndexOf函数会尝试将参数array转换为Object[],无论成功与否,都会进行参数value是否为null的判断,然后for循环判断出结果。
// Inserts an element into this list at a given index. The size of the list
// is increased by one. If required, the capacity of the list is doubled
// before inserting the new element.
//
public virtual void Insert(int index, Object value) {
// Note that insertions at the end are legal.
if (index < 0 || index > _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_ArrayListInsert"));
//Contract.Ensures(Count == Contract.OldValue(Count) + 1);
Contract.EndContractBlock();
if (_size == _items.Length) EnsureCapacity(_size + 1);
//插入到内部数组头部或中间,尾部是合法的
if (index < _size) {
Array.Copy(_items, index, _items, index + 1, _size - index);
}
_items[index] = value;
_size++;
_version++;
}
// Inserts the elements of the given collection at a given index. If
// required, the capacity of the list is increased to twice the previous
// capacity or the new size, whichever is larger. Ranges may be added
// to the end of the list by setting index to the ArrayList's size.
//
public virtual void InsertRange(int index, ICollection c) {
if (c==null)
throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection"));
if (index < 0 || index > _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
//Contract.Ensures(Count == Contract.OldValue(Count) + c.Count);
Contract.EndContractBlock();
int count = c.Count;
if (count > 0) {
//进行扩容,接收数据
EnsureCapacity(_size + count);
// shift existing items
//插入到内部数组头部或中间,尾部是合法的
if (index < _size) {
Array.Copy(_items, index, _items, index + count, _size - index);
}
Object[] itemsToInsert = new Object[count];
c.CopyTo(itemsToInsert, 0);
itemsToInsert.CopyTo(_items, index);
_size += count;
_version++;
}
}
// Returns the index of the last occurrence of a given value in a range of
// this list. The list is searched backwards, starting at the end
// and ending at the first element in the list. The elements of the list
// are compared to the given value using the Object.Equals method.
//
// This method uses the Array.LastIndexOf method to perform the
// search.
//
public virtual int LastIndexOf(Object value)
{
Contract.Ensures(Contract.Result() < _size);
return LastIndexOf(value, _size - 1, _size);
}
// Returns the index of the last occurrence of a given value in a range of
// this list. The list is searched backwards, starting at index
// startIndex and ending at the first element in the list. The
// elements of the list are compared to the given value using the
// Object.Equals method.
//
// This method uses the Array.LastIndexOf method to perform the
// search.
//
public virtual int LastIndexOf(Object value, int startIndex)
{
if (startIndex >= _size)
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
Contract.Ensures(Contract.Result() < Count);
Contract.EndContractBlock();
return LastIndexOf(value, startIndex, startIndex + 1);
}
// Returns the index of the last occurrence of a given value in a range of
// this list. The list is searched backwards, starting at index
// startIndex and upto count elements. The elements of
// the list are compared to the given value using the Object.Equals
// method.
//
// This method uses the Array.LastIndexOf method to perform the
// search.
//
public virtual int LastIndexOf(Object value, int startIndex, int count) {
if (Count != 0 && (startIndex < 0 || count < 0))
throw new ArgumentOutOfRangeException((startIndex<0 ? "startIndex" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.Ensures(Contract.Result() < Count);
Contract.EndContractBlock();
if (_size == 0) // Special case for an empty list
return -1;
if (startIndex >= _size || count > startIndex + 1)
throw new ArgumentOutOfRangeException((startIndex>=_size ? "startIndex" : "count"), Environment.GetResourceString("ArgumentOutOfRange_BiggerThanCollection"));
return Array.LastIndexOf((Array)_items, value, startIndex, count);
}
和List一样最终调用Array.LastIndexOf函数,其实现如下:
// Returns the index of the last occurrence of a given value in a range of
// an array. The array is searched backwards, starting at index
// startIndex and counting uptocount elements. The elements of
// the array are compared to the given value using the Object.Equals
// method.
//
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int LastIndexOf(Array array, Object value, int startIndex, int count) {
if (array==null)
throw new ArgumentNullException("array");
Contract.Ensures(Contract.Result() < array.GetLowerBound(0) + array.Length);
Contract.EndContractBlock();
int lb = array.GetLowerBound(0);
if (array.Length == 0) {
return lb-1;
}
if (startIndex < lb || startIndex >= array.Length + lb)
throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
if (count > startIndex - lb + 1)
throw new ArgumentOutOfRangeException("endIndex", Environment.GetResourceString("ArgumentOutOfRange_EndIndexStartIndex"));
if (array.Rank != 1)
throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
// Try calling a quick native method to handle primitive types.
int retVal;
bool r = TrySZLastIndexOf(array, startIndex, count, value, out retVal);
if (r)
return retVal;
Object[] objArray = array as Object[];
int endIndex = startIndex - count + 1;
if (objArray!=null) {
if (value == null) {
for (int i = startIndex; i >= endIndex; i--) {
if (objArray[i] == null) return i;
}
}
else {
for (int i = startIndex; i >= endIndex; i--) {
Object obj = objArray[i];
if (obj != null && obj.Equals(value)) return i;
}
}
}
else {
for (int i = startIndex; i >= endIndex; i--) {
Object obj = array.GetValue(i);
if( obj == null) {
if(value == null) return i;
}
else {
if( obj.Equals(value)) return i;
}
}
}
return lb-1; // Return lb-1 for arrays with negative lower bounds.
}
和Array.IndexOf实现相同,只不过否循环是从后向前。
// Removes the element at the given index. The size of the list is
// decreased by one.
//
#if !FEATURE_CORECLR
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
//内部调用IndexOf查找索引位置,通过RemoveAt移除,所以在知道索引的清空下,尽量使用RemoveAt
public virtual void Remove(Object obj) {
Contract.Ensures(Count >= 0);
int index = IndexOf(obj);
BCLDebug.Correctness(index >= 0 || !(obj is Int32), "You passed an Int32 to Remove that wasn't in the ArrayList." + Environment.NewLine + "Did you mean RemoveAt? int: "+obj+" Count: "+Count);
if (index >=0)
RemoveAt(index);
}
// Removes the element at the given index. The size of the list is
// decreased by one.
//
public virtual void RemoveAt(int index) {
if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
Contract.Ensures(Count >= 0);
//Contract.Ensures(Count == Contract.OldValue(Count) - 1);
Contract.EndContractBlock();
_size--;
if (index < _size) {
//将不需要移除的元素向上移动,注意此时的_size已经更新过
Array.Copy(_items, index + 1, _items, index, _size - index);
}
_items[_size] = null;
_version++;
}
// Removes a range of elements from this list.
//
public virtual void RemoveRange(int index, int count) {
if (index < 0)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (_size - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
Contract.Ensures(Count >= 0);
//Contract.Ensures(Count == Contract.OldValue(Count) - count);
Contract.EndContractBlock();
if (count > 0) {
int i = _size;
_size -= count;
if (index < _size) {
//将不需要移除的元素向上移动,注意此时的_size已经更新过
Array.Copy(_items, index + count, _items, index, _size - index);
}
while (i > _size) _items[--i] = null;
_version++;
}
}
// Reverses the elements in this list.
public virtual void Reverse() {
Reverse(0, Count);
}
// Reverses the elements in a range of this list. Following a call to this
// method, an element in the range given by index and count
// which was previously located at index i will now be located at
// index index + (index + count - i - 1).
//
// This method uses the Array.Reverse method to reverse the
// elements.
//
public virtual void Reverse(int index, int count) {
if (index < 0)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (_size - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
Contract.EndContractBlock();
Array.Reverse(_items, index, count);
_version++;
}
调用Array.Reverse函数,其实现如下:
// Reverses the elements in a range of an array. Following a call to this
// method, an element in the range given by index and count
// which was previously located at index i will now be located at
// index index + (index + count - i - 1).
// Reliability note: This may fail because it may have to box objects.
//
[System.Security.SecuritySafeCritical] // auto-generated
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static void Reverse(Array array, int index, int length) {
if (array==null)
throw new ArgumentNullException("array");
if (index < array.GetLowerBound(0) || length < 0)
throw new ArgumentOutOfRangeException((index<0 ? "index" : "length"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - (index - array.GetLowerBound(0)) < length)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
if (array.Rank != 1)
throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
Contract.EndContractBlock();
bool r = TrySZReverse(array, index, length);
if (r)
return;
int i = index;
//注意length为反转的数量
int j = index + length - 1;
Object[] objArray = array as Object[];
if (objArray!=null) {
while (i < j) {
Object temp = objArray[i];
objArray[i] = objArray[j];
objArray[j] = temp;
i++;
j--;
}
}
else {
while (i < j) {
Object temp = array.GetValue(i);
array.SetValue(array.GetValue(j), i);
array.SetValue(temp, j);
i++;
j--;
}
}
}
// Sorts the elements in this list. Uses the default comparer and
// Array.Sort.
public virtual void Sort()
{
Sort(0, Count, Comparer.Default);
}
// Sorts the elements in this list. Uses Array.Sort with the
// provided comparer.
public virtual void Sort(IComparer comparer)
{
Sort(0, Count, comparer);
}
// Sorts the elements in a section of this list. The sort compares the
// elements to each other using the given IComparer interface. If
// comparer is null, the elements are compared to each other using
// the IComparable interface, which in that case must be implemented by all
// elements of the list.
//
// This method uses the Array.Sort method to sort the elements.
//
public virtual void Sort(int index, int count, IComparer comparer) {
if (index < 0)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (_size - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
Contract.EndContractBlock();
Array.Sort(_items, index, count, comparer);
_version++;
}
调用Array.Sort函数。
注:本人水平有限,如果有错误,欢迎指正……