C# ArrayList原始碼剖析
原始碼版本為 .NET Framework 4.6.1
本系列持續更新,敬請關注
有投入,有產出。
陣列是C#中最基礎的一種資料型別,一旦初始化之後,容量便已經確定。若想要動態擴充容量,那麼集合可以滿足這點需求。ArrayList是C#最常用也是最基礎的一個動態陣列。
ArrayList在System.Collections中,實現了IList介面(IList:表示可按照索引進行訪問的非泛型集合物件)。
如此來,ArrayList可以乾點什麼事情呢?
1. 可以動態擴容;
2. 插入/刪除 比較便捷;
為了防止廢話過多而導致翻船,上程式碼:
- ArrayList中的資料是由一個內部陣列來進行維護的,一個私有的Object資料(Object 你就是萬能的造物主啊~)
private Object[] _item[];
private int _size;//ArrayList的容量
private const int _defaultCapacity = 4;//預設的容量
private static readonly Object[] emptyArray = EmptyArray<Object>.Value; //預設的空陣列
- 新增元素:Add(Object) ,AddRange(ICollection),Insert(Int32, Object),InsertRange(Int32, ICollection)。
- Add(Object):將物件新增到 ArrayList 的結尾處。
public virtual int Add(Object value) {
Contract.Ensures(Contract.Result<int>() >= 0);//後置契約,返回值必須大於等於0
//動態擴容的核心方法,當ArrayList的容量等於內部存放資料的陣列長度時,進行擴容
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size] = value;//在ArrayList末尾索引處寫入值
_version++;
return _size++;//返回陣列ArrayList的容量
}
//動態擴容的核心方法,一次擴容長度為初始容量的2倍,容量不得超出long的最大範圍
private void EnsureCapacity(int min) {
if (_items.Length < min) {
int newCapacity = _items.Length == 0
? _defaultCapacity: _items.Length * 2;
//Array.MaxArrayLength為long的最大值
if ((uint)newCapacity > Array.MaxArrayLength)
newCapacity = Array.MaxArrayLength;
if (newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
}
//自動擴容的實現原理是 建立一個更大容量新的組數,將原陣列的資料搬至新組數
public virtual int Capacity {
get {
Contract.Ensures(Contract.Result<int>() >= Count);
return _items.Length;
}
set {
if (value < _size) {
throw new ArgumentOutOfRangeException("value",
Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
}
Contract.Ensures(Capacity >= 0);
Contract.EndContractBlock();
if (value != _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];
}
}
}
}
2. AddRange(ICollection):新增 ICollection 的元素到 ArrayList 的末尾。該方法在內部呼叫了InsertRange(Int32, ICollection)方法
public virtual void AddRange(ICollection c) {
InsertRange(_size, c);
}
3. Insert(Int32, Object) :將元素插入 ArrayList 的指定索引處。
public virtual void Insert(int index, Object value) {
if(index < 0 || index > _size)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_ArrayListInsert"));
Contract.EndContractBlock();
//擴容檢查
if(_size == _items.Length) EnsureCapacity(_size + 1);
//插入到指定索引處,可以看出,由於需要移動元素的位置,相對於Add直接插入到末尾來說,效率慢了點
if(index < _size){
Array.Copy(_items, index, _items, index + 1, _size - index);
}
_items[index] = value;
_size++;
_version++;
}
4. InsertRange(Int32, ICollection):將ICollection中的元素插入到 ArrayList 中指定索引處。
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.EndContractBlock();//契約結尾
int count = c.Count;//即將要新增到ArrayList的元素數量
if (count > 0) {
//每次新增元素,都會進行擴容判斷
EnsureCapacity(_size + count);
//友誼的小船說翻就翻,看看微軟大神在功能與效能上所做的取捨吧
if (index < _size) {
//移動元素位置
Array.Copy(_items, index, _items, index + count, _size - index);
}
//後面這段沒有用for迴圈,也許是微軟大神為了程式碼的重用吧?
//建立新陣列用於儲存即將插入ArrayList的元素
Object[] itemsToInsert = new Object[count];
c.CopyTo(itemsToInsert, 0);
//將元素插入對應的索引處
itemsToInsert.CopyTo(_items, index);
_size += count;
_version++;
}
}
- 移除元素:Remove(Object),RemoveAt(Int32),RemoveRange(Int32, Int32),Clear()。
- Remove(Object):從 ArrayList 中移除特定物件的第一個匹配項。在內部呼叫了IndexOf(Int32)和RemoveAt(Int32)。
public virtual void Remove(Object obj) {
Contract.Ensures(Count >= 0);
//呼叫IndexOf(Int32)獲取元素的索引
int index = IndexOf(obj);
if(index >= 0)
RemoveAt(index);
}
2.RemoveAt(Int32):移除 ArrayList 的指定索引處的元素。
public virtual void RemoveAt(int index) {
if (index < 0 || index >= _size)
throw new ArgumentOutOfRangeException("index",
Environment.GetResourceString("ArgumentOutOfRange_Index"));
Contract.Ensures(Count >= 0);
Contract.EndContractBlock();
_size--;//移除元素,容量自減1
//移除元素也會導致元素位置的變動,導致效率降低
if (index < _size) {
Array.Copy(_items, index + 1, _items, index, _size - index);
}
_items[_size] = null;
_version++;
}
3.RemoveRange(Int32, Int32):從 ArrayList 中移除一定範圍的元素。
public virtual void Clear() {
if (_size > 0)
{
//快刀斬亂麻
Array.Clear(_items, 0, _size);
_size = 0;
}
_version++;
}
- 排序:Sort(),Sort(IComparer),Sort(Int32, Int32, IComparer),Reverse(),Reverse(Int32, Int32)
- Sort():將整個 ArrayList 中的元素進行排序。在ArrayList的排序方法全部在內部呼叫了Sort(Int32, Int32, IComparer),進行排序。
- Sort(IComparer):使用指定的比較器對整個 ArrayList 中的元素進行排序。
- Sort(Int32, Int32, IComparer):使用指定的比較器對 ArrayList 中某個範圍內的元素進行排序。
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++;
}
4.Reverse():將整個 ArrayList 中元素的順序反轉。
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++;
}
5.Reverse(Int32, Int32):將指定範圍中元素的順序反轉。
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++;
}
ArrayList可以說是C#中最簡單的一種資料結構了,再使用ArrayList時為了獲得一些效能上的提升,儘量在可預知的容量大小範圍內使用一個固定的初始容量來構建ArrayList了,以使在某些情況下,可以避免內部陣列的重複建立和資料位置的變換。
相關推薦
C# ArrayList原始碼剖析
原始碼版本為 .NET Framework 4.6.1 本系列持續更新,敬請關注 有投入,有產出。 陣列是C#中最基礎的一種資料型別,一旦初始化之後,容量便已經確定。若想要動態擴充容量,那麼集合可以滿足這點需求。ArrayList是C#最常用也是最基礎
ArrayList原始碼剖析~
包路徑:package java.util; 一、基本屬性 1、private static final long serialVersionUID = 8683452581122892189L;  
C++ STL原始碼剖析——stl_alloc.h
stl_alloc.h # // Comment By: 凝霜 # // E-mail: [email protected] # // Blog: http://blog.csdn.net/mdl13412 # # //
C# Hashtable原始碼剖析
原始碼版本為 .NET Framework 4.6.1 本系列持續更新,敬請關注 有投入,有產出。 Hashtable實現一個雜湊表(也叫散列表),將鍵對映到相應的值。任何非 null 物件都可以用作鍵。 雜湊表的實現比較複雜,最好先了解一下相關的方
【實踐】Zookeeper c client原始碼剖析——不同event觸發的條件和時機
watcher,watcherCtx));//關鍵語句:add_stat_completion函式往zh->sent_requests(即傳送請求佇列)中新增非同步完成資料結構物件(包括非同步回撥型別COMPLETION_STAT和回撥函式地址,同時該物件中還儲存著當關注的事件發生時要回調的watch
【Java集合原始碼剖析】ArrayList原始碼剖析
本篇博文參加了CSDN博文大賽,如果您覺得這篇博文不錯,希望您能幫我投一票,謝謝!ArrayList簡介 ArrayList是基於陣列實現的,是一個動態陣列,其容量能自動增長,類似於C語言中的動態申請記憶體,動態增長記憶體。 ArrayList不是執行緒安全的,只
ArrayList原始碼剖析與程式碼實測
# ArrayList原始碼剖析與程式碼實測(基於OpenJdk14) [toc] * 寫本篇部落格的目的在於讓自己能夠更加了解Java的容器與實現,能夠掌握原始碼的一些實現與思想,選擇從ArrayList入手是因為ArrayList相對來說是實現較為簡單的容器,底層實現依賴與陣列,將ArrayList整
【原始碼剖析】tinyhttpd —— C 語言實現最簡單的 HTTP 伺服器
tinyhttpd 是一個不到 500 行的超輕量型 Http Server,用來學習非常不錯,可以幫助我們真正理解伺服器程式的本質。 看完所有原始碼,真的感覺有很大收穫,無論是 unix 的程式設計,還是 GET/POST 的 Web 處理流程
【Linux 1.0核心原始碼剖析】執行程式——exec.c
父程序 fork的子程序的目的自然不是建立一個幾乎與自己一模一樣的程序。而是通過子程序呼叫 exec 函式簇去執行另外一個程式。exec() 系統呼叫必須定位該執行檔案的二進位制映像,載入並執行它。 exec() 的Linux實現支援不同的二進位制格式,這是通過 linux
【特徵匹配】SIFT原理與C原始碼剖析
SIFT的原理已經有很多大牛的部落格上做了解析,本文重點將以Rob Hess等人用C實現的程式碼做解析,結合程式碼SIFT原理會更容易理解。一些難理解點的用了☆標註。 歡迎大家批評指正! 轉載請註明出處:http://blog.csdn.net/l
【Linux 核心網路協議棧原始碼剖析】socket.c——BSD Socket層(1)
寫在前面:本系列文章先把各個層對應的檔案原始碼剖析一遍,最後再穿插起來,理清整個協議棧網路資料包的上下傳送通道,從整體實現上進行把握。 圖片來源於《Linux 核心網路棧原始碼情景分析》 更上層函式:tcp socket函式介紹。本篇則是介紹BSD Sock
【學習筆記】C# ArrayList
tde 獲取 style demo key ren mov cnblogs content 集合 集合是種容器,在程序中,使用集體管理相關對象組 集合分為非泛型集合和泛型集合 非泛型集合 使用非泛型集合需要引入命名空間System.Collections Arra
(3.2)狄泰軟件學院C++課程學習剖析三
cti 學院 函數定義 關鍵字 但是 function 判斷 ima c語言 對課程前面40課的詳細回顧分析 1、 2、 3、c++中可以使用const常量代替宏常數定義;同樣我們可以使用內聯函數來替代宏代碼片段。內聯函數在聲明時inline關鍵字必須和函數定義
C# ArrayList的用法
知新樹 寧金峰ArrayList類是一個特殊的數組。通過添加和刪除元素,就可以動態改變數組的長度。一、優點1. 支持自動改變大小的功能2. 可以靈活的插入元素3. 可以靈活的刪除元素4. 可以靈活訪問元素二、局限性跟一般的數組比起來,速度上差些用微軟的話講:“添加到 ArrayList 中的任何引用或值類型都
C語言深度剖析 -- 第一課 基本數據類型
中一 eof bsp div pri style pre short 一段 第一課 -- 基本數據類型分析 任何編程語言,它都要操作存在內存中的數據, 變量的本質是內存中一段數據空間的別名 1 #include <stdlib.h>
《C語言深度剖析》筆記
可變 單詞 符號 所有 只讀 存儲 nbsp min stat 關鍵字: C語言關鍵字32個: 關鍵字 意 義 auto 聲明自動變量,
菜鳥帶你看原始碼——看不懂你打我ArrayList原始碼分析(基於java 8)
文章目錄 看原始碼並不難 軟體環境 成員變數: 構造方法 核心方法 get方法 remove方法 add方法 結束 看原始碼並不難 如何學好程式設計?如何寫出優質的程式碼?如
python重試庫retryiny原始碼剖析
上篇博文介紹了常見需要進行請求重試的場景,本篇博文試著剖析有名的python第三方庫retrying原始碼。 在剖析其原始碼之前,有必要講一下retrying的用法,方便理解。 安裝: pip install retryin
Caffe框架原始碼剖析(6)—池化層PoolingLayer
卷積層ConvolutionLayer正向傳導的目標層往往是池化層PoolingLayer。池化層通過降取樣來降低卷積層輸出的特徵向量,同時改善結果,不易出現過擬合。最常用的降取樣方法有均值取樣(取區域平均值作為降取樣值)、最大值取樣(取區域最大值作為降取樣值)和隨機
Caffe框架原始碼剖析(5)—卷積層ConvolutionLayer
ConvolutionLayer是BaseConvolutionLayer的子類,功能較為簡單。類中不包含成員變數,僅包含幾個虛擬函式的實現。 conv_layer.hpp標頭檔案的定義如下: template <typename Dtype> class Convoluti