.NET,你忘記了麼?(三續)——重新理解List
在上文中,我對List
的理解大錯特錯,在成文前,首先做下自我批評,然後也對造成的不良影響表示道歉。 週四面試的慘敗,讓我的心情著實糟糕了兩三天。痛定思痛,決心回家繼續苦讀。
首先開始的就是對List的重新認知。在這裡,讓我們先從構造方法來重新認識List
的本質,先來看下上文中我所粘出的程式碼: List<int> list = new List<int>(); for (int i = 0; i < 10; i++) { list.Add(i); } Random r = new Random(); for (int j = 0; j < 100; j++) { int temp; int x1 = r.Next(10); int x2 = r.Next(10); temp = list[x1]; list[x1] = list[x2]; list[x2] = temp; }在上文中,我對這個List大批特批,現在,我們來重新看下這個List的構造:public List() { this._items = List._emptyArray; } 先來看無參的構造方法,當無參的時候,.NET Framework其實是用一個_emptyArray來初始化了List中的items集合。那麼_emptyArray又是什麼呢?我們繼續向下看:
private static T[] _emptyArray;
恩,他是一個靜態欄位,然後我們看下List
的靜態構造方法: static List() { List._emptyArray = new T[0]; } 我們看到,_emptyArray其實是一個T型別的陣列,個數為0。那麼也就是說,當我們執行0引數的構造方法時,系統是把items集合給賦值為了一個T型別的個數為0的陣列。
那麼items又是什麼?我們繼續向下看:
public void Add(T item) { if (this._size == this._items.Length) { this.EnsureCapacity(this._size + 1); } this._items[this._size++] = item; this._version++; }這是List
中一個Add(T item)方法,但是我們可以從方法中敲出些端倪來。 在這裡,我並不是想解釋這個方法的原理,只是想說,在List中,其實維護這一個items,然後很多操作,是基於items的操作。
恩,所以在上文中,List
list=new List ();和Array a=new int[10]();的操作其實差別並不大。 我們肯定還記得在《Effective C#》中有這樣一條規則,就是說:在初始化List之前最好對List初始化大小。
讓我們從原始碼中來找到這一條規則的答案。
private void EnsureCapacity(int min) { if (this._items.Length < min) { int num = (this._items.Length == 0) ? 4 :
(this._items.Length * 2); if (num < min) { num = min; } this.Capacity = num; } }我們來看,在這個方法體中,List會新建一個陣列,然後把陣列的長度設定為原來的二倍(如果原有的陣列長度為0,那就預設將陣列的長度設定為4)。
因此,這種,讓List的方法自己去呼叫EnsureCapacity(int min)方法,不僅浪費了構造陣列的時間,還浪費了大量的空間(因為將原有的陣列空間擴充了二倍)。
因此,請記得:在初始化List之前最好指定List的大小。
為了證明上述的觀點,我們再來隨便看一些程式碼:
public int IndexOf(T item) { return Array.IndexOf(this._items, item, 0, this._size); }
public int FindIndex(int startIndex, int count,
Predicatematch) { if (startIndex > this._size) { ThrowHelper.ThrowArgumentOutOfRangeException
(ExceptionArgument.startIndex, ExceptionResource.
ArgumentOutOfRange_Index); } if ((count < 0) || (startIndex > (this._size - count))) { ThrowHelper.ThrowArgumentOutOfRangeException
(ExceptionArgument.count, ExceptionResource.
ArgumentOutOfRange_Count); } if (match == null) { ThrowHelper.ThrowArgumentNullException
(ExceptionArgument.match); } int num = startIndex + count; for (int i = startIndex; i < num; i++) { if (match(this._items[i])) { return i; } } return -1; }
由上面的程式碼,我想證明的是:其實List
不過是對Array的進一步封裝 ,說得再直接點,我願意理解List為Array的可擴充版本,然後擴充套件了一些方法; 那關於Array和List的選擇,我重新做一個說明:
List是基於Array存在的,因此,在建立一個List物件時,需要耗費比Array相對更多的時間,以及更大的空間,因為List除了初始化內部的items外還需要初始化一些其他的屬性。而且在方法呼叫時,這點我沒有證實,只是一個猜測,List需要的是再去呼叫Array的相關方法,因此也許會存在方法呼叫的時間消耗問題。
因此,我的建議是:
如果初始化時確定大小,那麼就使用Array。
如果初始化時不確定大小,那麼就使用List。當然,其實完全可以自己去實現List中的陣列擴充功能的,也許會更棒,因為我們沒有必要去將Array每次都擴充為原來的二倍。
另外,非主流程式設計師的補充,Array相對於List還有個優勢就是:多維陣列比List的巢狀更容易理解,也就是說int[][](或者是int[,])要強於List>,也就說在型別確定且多維的情況下,用Array要優於List。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-580344/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 你的INTERNAL帳號密碼忘記了怎麼辦(轉)密碼
- mysql密碼忘記了怎麼辦MySql密碼
- Wifi密碼忘記了怎麼辦WiFi密碼
- MySQL初始密碼忘記了怎麼辦MySql密碼
- 忘記管理員密碼了怎麼辦密碼
- 網站密碼忘記了怎麼修改?網站密碼
- 好久不更新了,居然忘記怎麼寫日誌了!
- win10本地密碼忘記怎麼辦_win10密碼忘記了怎麼解鎖Win10密碼
- excel密碼忘記了怎麼解鎖 excel忘記密碼怎樣簡單找回Excel密碼
- Linux-mongo 密碼忘記了怎麼辦LinuxGo密碼
- 織夢網站密碼忘記了怎麼辦?網站密碼
- win10開機密碼忘記了怎麼辦 win10開機密碼忘記了的方法Win10密碼
- iPhone忘記訪問限制密碼的解決辦法 密碼忘記了怎麼辦?iPhone密碼
- 想登入寶塔皮膚但是忘記密碼_寶塔密碼忘記了怎麼辦密碼
- PbootCMS忘記登入密碼怎麼辦?忘記了PBootCMS後臺的登入密碼boot密碼
- 經常忘記了檔案放在什麼地方?這款工具你可以看一下
- 電腦密碼忘記了怎麼解開 圖文詳解電腦密碼忘記了的解開方法密碼
- linux系統root密碼忘記了怎麼辦Linux密碼
- Win8系統密碼忘記了怎麼辦密碼
- 帝國cms忘記了後臺密碼怎麼辦密碼
- 如果程式碼審查時你忘記了拿近視眼鏡
- 付了款,忘記取密碼了。。。。。。密碼
- 抖音找回密碼教程 抖音密碼忘記了怎麼辦密碼
- 忘記了無線路由器的密碼怎麼辦?路由器密碼
- linux忘記了密碼怎麼辦(lilo/grub)(轉)Linux密碼
- 網站後臺帳號密碼忘記了怎麼辦網站密碼
- 你真的理解 getLocationInWindow 了嗎?
- 你真的理解 new 了嗎?
- JAVA 面試,你常常忘記它們Java面試
- 【少用會忘】PHP 函式筆記(持續更新)PHP函式筆記
- iOS開發備忘筆記 (持續更新中)iOS筆記
- 網站密碼忘記了?網站忘了密碼怎麼辦網站密碼
- 電腦開機密碼忘記的六種解決方法 電腦開機密碼忘記了怎麼辦?密碼
- win10安全模式啟動忘記初始密碼怎麼辦_win10安全模式初始密碼忘記了怎麼解決Win10模式密碼
- .NET程式崩潰了怎麼抓 Dump ? 我總結了三種方案
- 三層,你真的理解了嗎?
- Java設計模式之三種工廠模式 -- 總是忘記,這次把你記下來!Java設計模式
- 哲學筆記——叔本華《續三》筆記