1
、什么是
ArrayList
????ArrayList
就是傳說中的動態(tài)數(shù)組,用
MSDN
中的說法,就是
Array
的復(fù)雜版本,它提供了如下一些好處:
-
動態(tài)的增加和減少元素
-
實現(xiàn)了
ICollection
和
IList
接口
-
靈活的設(shè)置數(shù)組的大小
2
、如何使用
ArrayList
????
最簡單的例子:
ArrayList?List?=?new?ArrayList();
for(?int?i=0;i<10;i++?)?//
給數(shù)組增加
10
個
Int
元素
List.Add(i);?
//..
程序做一些處理
List.RemoveAt(5);//
將第
6
個元素移除
for(?int?i=0;i<3;i++?)?//
再增加
3
個元素
? List.Add(i+20);
Int32[]?values?=?(Int32[])List.ToArray(typeof(Int32));//
返回
ArrayList
包含的數(shù)組
這是一個簡單的例子,雖然沒有包含
ArrayList
所有的方法,但是可以反映出
ArrayList
最常用的用法
3
、
ArrayList
重要的方法和屬性
(
1
)構(gòu)造器
????ArrayList
提供了三個構(gòu)造器:
public?ArrayList();
默認(rèn)的構(gòu)造器,將會以默認(rèn)(
16
)的大小來初始化內(nèi)部的數(shù)組
public?ArrayList(ICollection);
用一個
ICollection
對象來構(gòu)造,并將該集合的元素添加到
ArrayList
public?ArrayList(int);
用指定的大小來初始化內(nèi)部的數(shù)組
(
2
)
IsSynchronized
屬性和
ArrayList.Synchronized
方法
????IsSynchronized
屬性指示當(dāng)前的
ArrayList
實例是否支持線程同步,而
ArrayList.Synchronized
靜態(tài)方法則會返回一個
ArrayList
的線程同步的封裝。
????
如果使用非線程同步的實例,那么在多線程訪問的時候,需要自己手動調(diào)用
lock
來保持線程同步,例如:
ArrayList?list?=?new?ArrayList();
//...
lock(?list.SyncRoot?)?//
當(dāng)
ArrayList
為非線程包裝的時候,
SyncRoot
屬性其實就是它自己,但是為了滿足
ICollection
的
SyncRoot
定義,這里還是使用
SyncRoot
來保持源代碼的規(guī)范性
{
list.Add(?
“
Add?a?Item
”
?);
}
?????
如果使用
ArrayList.Synchronized
方法返回的實例,那么就不用考慮線程同步的問題,這個實例本身就是線程安全的,實際上
ArrayList
內(nèi)部實現(xiàn)了一個保證線程同步的內(nèi)部類,
ArrayList.Synchronized
返回的就是這個類的實例,它里面的每個屬性都是用了
lock
關(guān)鍵字來保證線程同步。
****
但是,使用這個方法(
ArrayList.Synchronized
)并不能保證枚舉的同步,例如,一個線程正在刪除或添加集合項,而另一個線程同時進行枚舉,這時枚舉將會拋出異常。所以,在枚舉的時候,你必須明確使用
SyncRoot
鎖定這個集合。
?
Hashtable
與
ArrayList
關(guān)于線程安全性的使用方法類似。
****
(
3
)
Count
屬性和
Capacity
屬性
????Count
屬性是目前
ArrayList
包含的元素的數(shù)量,這個屬性是只讀的。
Capacity
屬性是目前
ArrayList
能夠包含的最大數(shù)量,可以手動的設(shè)置這個屬性,但是當(dāng)設(shè)置為小于
Count
值的時候會引發(fā)一個異常。
(
4
)
Add
、
AddRange
、
Remove
、
RemoveAt
、
RemoveRange
、
Insert
、
InsertRange
????
這幾個方法比較類似
Add
方法用于添加一個元素到當(dāng)前列表的末尾
AddRange
方法用于添加一批元素到當(dāng)前列表的末尾
Remove
方法用于刪除一個元素,通過元素本身的引用來刪除
RemoveAt
方法用于刪除一個元素,通過索引值來刪除
RemoveRange
用于刪除一批元素,通過指定開始的索引和刪除的數(shù)量來刪除
Insert
用于添加一個元素到指定位置,列表后面的元素依次往后移動
InsertRange
用于從指定位置開始添加一批元素,列表后面的元素依次往后移動
????
另外,還有幾個類似的方法:
Clear
方法用于清除現(xiàn)有所有的元素
Contains
方法用來查找某個對象在不在列表之中
????
其他的我就不一一累贅了,大家可以查看
MSDN
,上面講的更仔細(xì)
(
5
)
TrimSize
方法
????
這個方法用于將
ArrayList
固定到實際元素的大小,當(dāng)動態(tài)數(shù)組元素確定不在添加的時候,可以調(diào)用這個方法來釋放空余的內(nèi)存。
(
6
)
ToArray
方法
????
這個方法把
ArrayList
的元素
Copy
到一個新的數(shù)組中。
4
、
ArrayList
與數(shù)組轉(zhuǎn)換
????
例
1
:
ArrayList?List?=?new?ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);
Int32[]?values?=?(Int32[])List.ToArray(typeof(Int32));
????
例
2
:
ArrayList?List?=?new?ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);
Int32[]?values?=?new?Int32[List.Count];
List.CopyTo(values);
????
上面介紹了兩種從
ArrayList
轉(zhuǎn)換到數(shù)組的方法
????
例
3
:
ArrayList?List?=?new?ArrayList();
List.Add(?
“
string
”
?);
List.Add(?1?);
//
往數(shù)組中添加不同類型的元素
object[]?values?=?List.ToArray(typeof(object)); //
正確
string[]?values?=?(string[])List.ToArray(typeof(string));?//
錯誤
和數(shù)組不一樣,因為可以轉(zhuǎn)換為
Object
數(shù)組,所以往
ArrayList
里面添加不同類型的元素是不會出錯的,但是當(dāng)調(diào)用
ArrayList
方法的時候,要么傳遞所有元素都可以正確轉(zhuǎn)型的類型或者
Object
類型,否則將會拋出無法轉(zhuǎn)型的異常。
5
、
ArrayList
最佳使用建議
????
這一節(jié)我們來討論
ArrayList
與數(shù)組的差別,以及
ArrayList
的效率問題
??
(
1
)
ArrayList
是
Array
的復(fù)雜版本
ArrayList
內(nèi)部封裝了一個
Object
類型的數(shù)組,從一般的意義來說,它和數(shù)組沒有本質(zhì)的差別,甚至于
ArrayList
的許多方法,如
Index
、
IndexOf
、
Contains
、
Sort
等都是在內(nèi)部數(shù)組的基礎(chǔ)上直接調(diào)用
Array
的對應(yīng)方法。
??
(
2
)內(nèi)部的
Object
類型的影響
?????????
對于一般的引用類型來說,這部分的影響不是很大,但是對于值類型來說,往
ArrayList
里面添加和修改元素,都會引起裝箱和拆箱的操作,頻繁的操作可能會影響一部分效率。
但是恰恰對于大多數(shù)人,多數(shù)的應(yīng)用都是使用值類型的數(shù)組。
消除這個影響是沒有辦法的,除非你不用它,否則就要承擔(dān)一部分的效率損失,不過這部分的損失不會很大。
??
(
3
)數(shù)組擴容
這是對
ArrayList
效率影響比較大的一個因素。
每當(dāng)執(zhí)行
Add
、
AddRange
、
Insert
、
InsertRange
等添加元素的方法,都會檢查內(nèi)部數(shù)組的容量是否不夠了,如果是,它就會以當(dāng)前容量的兩倍來重新構(gòu)建一個數(shù)組,將舊元素
Copy
到新數(shù)組中,然后丟棄舊數(shù)組,在這個臨界點的擴容操作,應(yīng)該來說是比較影響效率的。
?????
例
1
:比如,一個可能有
200
個元素的數(shù)據(jù)動態(tài)添加到一個以默認(rèn)
16
個元素大小創(chuàng)建的
ArrayList
中,將會經(jīng)過:
16*2*2*2*2?=?256
四次的擴容才會滿足最終的要求,那么如果一開始就以:
ArrayList?List?=?new?ArrayList(?210?);
的方式創(chuàng)建
ArrayList
,不僅會減少
4
次數(shù)組創(chuàng)建和
Copy
的操作,還會減少內(nèi)存使用。
?????
例
2
:預(yù)計有
30
個元素而創(chuàng)建了一個
ArrayList
:
ArrayList?List?=?new?ArrayList(30);
在執(zhí)行過程中,加入了
31
個元素,那么數(shù)組會擴充到
60
個元素的大小,而這時候不會有新的元素再增加進來,而且有沒有調(diào)用
TrimSize
方法,那么就有
1
次擴容的操作,并且浪費了
29
個元素大小的空間。如果這時候,用:
ArrayList?List?=?new?ArrayList(40);
那么一切都解決了。
所以說,正確的預(yù)估可能的元素,并且在適當(dāng)?shù)臅r候調(diào)用
TrimSize
方法是提高
ArrayList
使用效率的重要途徑。
???
(
4
)頻繁的調(diào)用
IndexOf
、
Contains
等方法(
Sort
、
BinarySearch
等方法經(jīng)過優(yōu)化,不在此列)引起的效率損失
首先,我們要明確一點,
ArrayList
是動態(tài)數(shù)組,它不包括通過
Key
或者
Value
快速訪問的算法,所以實際上調(diào)用
IndexOf
、
Contains
等方法是執(zhí)行的簡單的循環(huán)來查找元素,所以頻繁的調(diào)用此類方法并不比你自己寫循環(huán)并且稍作優(yōu)化來的快,如果有這方面的要求,建議使用
Hashtable
或
SortedList
等鍵值對的集合。
ArrayList?al=new?ArrayList();
al.Add("How");
al.Add("are");
al.Add("you!");
al.Add(100);
al.Add(200);
al.Add(300);
al.Add(1.2);
al.Add(22.8);
.........
//
第一種遍歷
?ArrayList?
對象的方法
foreach(object?o?in?al)
{
Console.Write(o.ToString()+"?");
}
//
第二種遍歷
?ArrayList?
對象的方法
IEnumerator?ie=al.GetEnumerator();
while(ie.MoveNext())
{
Console.Write(ie.Curret.ToString()+"?");
}
//
第三種遍歷
?ArrayList?
對象的方法
我忘記了
,
好象是
?
利用
?ArrayList
對象的一個屬性
,
它返回一此對象中的元素個數(shù)
.
然后在利用索引
?
for(int?i=0;i<Count;i++)
{
Console.Write(al[i].ToString()+"?");
}?