浅谈 ArrayList 内部原理

System.Collections.ArrayList 就是我们常说的动态数组,也是我们常用的 "数据类型" 之一。
在 MSDN 上是这样表述的:使用大小可按需动态增加的数组实现 IList 接口。
我来解释一下,就是:一个可以根据需要动态增加使用大小并可按照索引单独访问的对象的非泛型集合。
一般人都认为 ArrayList 就是一个 "纯动态" 的数组,与 <数据结构> 中 "链表" 的原理一样。
在对 ArrayList 做深入探究和学习之前,我也是这么认为的。可是,事实并非如此。

在 ArrayList 内部有一个 Object 类型的数组,当第一次添加元素的时候,将其初始化并把容量设置为 4。
如果,当前的数组还有剩余空间的话,那我们就可以直接将元素添加到相应的位置。
否则,当数组空间已经用完时,.NET 运行库会创建一个新的数组,数组的空间是原来的两倍,并将原有数组中的元素拷贝到新数组中。
最后,将新数组的地址赋给老数组的变量。

我们来看下面一段代码:

  1     public class ArrayList
2 {
3 /// <summary>
4         /// 默认容量
5        /// </summary>
6 private const int defaultCapacity = 4;
7
8 /// <summary>
9         /// 当前数组中元素的数量
10         /// </summary>
11 private int size;
12
13 /// <summary>
14         /// 用于存放元素的数组
15         /// </summary>
16 private object[] items;
17
18 /// <summary>
19         /// 用于初始化 items 的静态只读 Object 类型数组
20         /// </summary>
21 private static readonly object[] emptyArray;
22
23 /// <summary>
24         /// 当前的最大容量
25         /// </summary>
26 public int Capacity
27 {
28 get
29 {
30 //返回当前数组的长度
31 return this.items.Length;
32 }
33 set
34 {
35 //设置的值不等于当前 items 数组的长度
36 if (value != this.items.Length)
37 {
38 if (value > 0)
39 {
40 //以设置的值为长度声明一个新的 Object 类型的数组
41 object[] destinationArray = new object[value];
42
43 if (this.size > 0)
44 {
45 //并将 items 数组中的元素拷贝到 destinationArray 数组中
46 Array.Copy(this.items, 0, destinationArray, 0, this.size);
47 }
48
49 //再将 destinationArray 赋给 items 数组
50 this.items = destinationArray;
51 }
52 else
53 {
54 this.items = new object[4];
55 }
56 }
57
58 }
59 }
60
61 /// <summary>
62        /// 静态构造函数
63         /// 把 emptyArray 初始化为一个容量为 0 的 Object 类型的数组。
64         /// </summary>
65 static ArrayList()
66 {
67 emptyArray = new object[0];
68 }
69
70 /// <summary>
71         /// 无参构造函数
72         /// 将 emptyArray 数组的值赋给 items 数组;
73         /// 也就是将 items 初始化一个容量为 0 的 Object 类型的数组。
74         /// </summary>
75 public ArrayList()
76 {
77 this.items = emptyArray;
78 }
79
80 /// <summary>
81         /// 增加元素的方法
82         /// </summary>
83         /// <param name="value">传入的对象</param>
84         /// <returns>当前添加元素的索引</returns>
85 public int Add(object value)
86 {
87 //如果当前数组中元素的数量等于 items 数组的长度的话
88 if (this.size == this.items.Length)
89 {
90 EnsureCapacity(this.size + 1);
91 }
92 //将传入进来的元素添加到 items 数组中
93 this.items[this.size] = value;
94 //返回当前元素在 items 数组中的索引
95 return this.size++;
96 }
97
98 /// <summary>
99         /// 确保满足容量
100         /// </summary>
101         /// <param name="min"></param>
102 private void EnsureCapacity(int min)
103 {
104 if (this.items.Length < min)
105 {
106 //如果当前的存放元素数组的长度等于0的话,num 就等于 4,否则 num 等于当前元素数组长度的两倍
107 int num = (this.items.Length == 0) ? 4 : (this.items.Length * 2);
108 if (num < min)
109 {
110 num = min;
111 }
112 //将当前的最大容量设置为 num
113 this.Capacity = num;
114 }
115 }
116 }

这段代码是我从 ArrayList 类的内部代码中抽离出来的一小部分,里面有详细的注释,我就不多说了。

posted @ 2012-02-17 22:40  AdamasTT  阅读(1863)  评论(6编辑  收藏  举报