ArrayList和Hashtable 很少在用,為什麼?
除了取數據不方便外,花費時間較多、效率低外,因為涉及到裝箱、拆箱的問題。
裝箱&拆箱
- 裝箱:將值類型轉成引用類型
- 拆箱:將引用類型轉成值類型
1
2
3
int n = 10;
object o = n; //裝箱
int nn = (int)o; //拆箱
ArrayList
值類型i放入引用類型ArrayList, 發生了裝箱
1
2
3
4
5
ArrayList list = new ArrayList();
//這個循環發生了1000萬次的裝箱操作
for (int i = 0; i < 10000000; i++) { //裝箱,裝了1000萬次
list.Add(i); //值類型`i`放入引用類型`ArrayList`, 發生了裝箱
}
驗証裝箱效率 ArrayList & List
ArrayList
ArrayList.Add();中的参數是Object類型,輸入的是int類型,所以發生了由實值型別到參考型別的轉換,裝箱。
1
2
3
4
5
6
7
8
9
10
11
12
13
ArrayList list = new ArrayList();
Stopwatch sw = new Stopwatch();
sw.Start();
//這個循環發生了1000萬次的裝箱操作
//00:00:18.721029
for (int i = 0; i < 10000000; i++) //裝箱,裝了1000000次
{ //值類型`i`放入引用類型`ArrayList`, 發生了裝箱
list.Add(i); //arraylist加入數據的類型,都是object類型,i都是int類型,所以發生了裝箱
}
sw.Stop();
Console.WriteLine(sw.Elapsed); //00:00:18.721029
Console.ReadKey();
耗費 00:00:18.721029 秒
List 泛型集合
泛型集合添加數據的類型,都是int類型,所以沒有發生裝箱
1
2
3
4
5
6
7
8
9
10
11
List<int> list = new List<int>();
Stopwatch sw = new Stopwatch();
sw.Start();
//00:00:03.1942654
for (int i = 0; i < 10000000; i++) {
list.Add(i); //泛型集合添加數據的類型,都是int類型,所以沒有發生裝箱
}
sw.Stop();
Console.WriteLine(sw.Elapsed); //00:00:03.1942654
Console.ReadKey()
耗費 00:00:03.1942654 秒
檢驗效能結果
ArrayList 和 List 跑1000萬次迴圈加入數值
得到結果:
00:00:18.721029 ArrayList
00:00:03.1942654 List
由上可知,裝箱會影響效能,因為一直在做類型轉換。
所以程式碼當中,避免裝箱。
裝箱&拆箱的判別
看兩種類型是否發生了裝箱或是拆箱,要看,這兩種類型是否存在繼承關係。
string轉換int
沒有發生任何類型的 裝箱&拆箱
1
2
string str =“123”;
int n = Convert.ToInt32(str);
上面程式碼,雖然是由參考類型(string)轉換為實值類型(int), 但是並沒有發生任何的裝箱和拆的操作,因為他們兩者(string 和 int)沒有繼承關係。
string 參考類型,是儲存在 Heap 堆積中
int 實值類型,是儲存在 Stack 堆疊中
int轉換IComparable
發生了裝箱
1
2
int n = 10;
IComparable i = n; //裝箱,IComparable是介面(參考型別),int繼承IComparable,有繼承關係
上述程式碼發生了裝箱: 首先int類型與IComparable類型是繼承關係,int繼承IComparable,有繼承關係,又是實值型別轉換成參考型別,所以發生了裝箱。
查看int定義
1
2
3
//Represents a 32-bit signed integer.
public readonly struct Int32 : IComparable, IComparable<Int32>, IConvertible, IEquatable<Int32>, ISpanFormattable, IFormattable
{ … }
int類型繼承了IComparable
參考型別 = 引用類型
實值型別 = 值類型