String和StringBuilder的深刻解析html
前言:本文出發點是咱們開發的過程當中是否真正的理解stringbuilder的使用,string字符串操做的是如何實現(哈希表),stringbuilder是否設置默認值容量,何時才用stringbuilder。安全
一律念String和stringbulider的理解app
string是咱們用的最多的類型之一,是一個特殊的引用類型,直接派生於Object,所以它的值儲存在託管堆上。構造一個新字符串的時候,不須要用new。它是」不可變的「。初始化字符串對象後,該字符串對象的長度、內容都是肯定不變的了。能夠思考這個時候,咱們須要更改或者添加字符串,會作一個怎樣的動做呢?ide
StringBulider由於string的」不可變「,致使屢次修改字符串的時候會損耗性能,.net爲了解決這個問題,提供了動態建立string的方法,以克服string不可變帶來的性能損耗。StringBuilder和String比起來,功能較少,只有基本的屬性和增刪改的方法。可是你知道stringbuilder也有一個固定的容量值嗎??,注意:StringBulider容量 (默認是16)雖然 StringBuilder 對象是動態對象,容許擴充它所封裝的字符串中字符的數量,可是您能夠爲它可容納的最大字符數指定一個值。此值稱爲該對象的容量,不該將它與當前 StringBuilder 對象容納的字符串長度混淆在一塊兒。例如,能夠建立 StringBuilder 類的帶有字符串「Hello」(長度爲 5)的一個新實例,同時能夠指定該對象的最大容量爲 25。當修改 StringBuilder 時,在達到容量以前,它不會爲其本身從新分配空間。當達到容量時,將自動分配新的空間且容量翻倍。可使用重載的構造函數之一來指定StringBuilder類的容量。如下代碼示例指定能夠將 MyStringBuilder對象擴充到最大25個空白。 StringBuilder MyStringBuilder = new StringBuilder("Hello World!", 25); 另外,能夠使用讀/寫 Capacity 屬性來設置對象的最大長度。如下代碼示例使用 Capacity 屬性來定義對象的最大長度。 MyStringBuilder.Capacity = 25; EnsureCapacity 方法可用來檢查當前 StringBuilder 的容量。若是容量大於傳遞的值,則不進行任何更改;可是,若是容量小於傳遞的值,則會更改當前的容量以使其與傳遞的值匹配。 也能夠查看或設置 Length 屬性。若是將 Length 屬性設置爲大於 Capacity 屬性的值,則自動將 Capacity 屬性更改成與 Length 屬性相同的值。若是將 Length 屬性設置爲小於當前 StringBuilder 對象內的字符串長度的值,則會縮短該字符串。函數
二、爲何說變更影響性能。(string和StringBuilder)性能
String:string s = "I am ";s += "Sky";怎麼分配內存的呢?
備註:若是每次都這樣從新分配真實瘋了,.net確定沒有那麼傻了,最起碼要避免下若是兩個string的字符串如出一轍,我是否是不須要分配新的堆,只須要制定一樣的引用就行了呢?下面就出現了一個名詞:字符串留用,CLR初始化的時候會建立哈希表,每構建一個新字符串都會與哈希表匹配,查找是否有相同的字符串,若是匹配,就會返回這個已存在的舊對象,由新變量進行引用。不然,就會建立一個字符串副本添加到哈希表裏,Key就是字符串,Value就是string對象在堆上的地址。測試
是否是全部的都是這樣呢,有什麼特殊狀況嗎?ui
總結New出來的對象是不會記錄在哈希表。.net
tringBuilder 對象維護一個緩衝區,以便容納新數據的串聯。若是有足夠的空間,新數據將被追加到緩衝區的末尾;不然,將分配一個新的、更大的緩衝區,原始緩衝區中的數據被複制到新的緩衝區,而後將新數據追加到新的緩衝區。pwa
內部實現原理
總結:StringBuffer是可變類,和線程安全的字符串操做類,任何對它指向的字符串的操做都不會產生新的對象。 每一個StringBuffer對象都有必定的緩衝區容量,當字符串大小沒有超過容量時,不會分配新的容量,當字符串大小超過容量時,會自動增長容量。事實是,StringBuilder比string快的緣由是string拼接時產生了中間對象,最終是垃圾。如: string str = "a";str += "b";str += "c";那麼,最終結果是"abc",但第二行產生了"ab"只是一箇中間對象,是個垃圾。用StringBuilder會避免這種中間對象的產生。那若是我這麼寫呢? string str ="a"+"b"+ "c";這會比StringBuilder慢嗎?不會。
中間對象的產生纔是影響性能的主要緣由。
3、測試案例:
private void button1_Click(object sender, EventArgs e)
{
int number =int.Parse( textBox1.Text.ToString());
GetStringTime(number);
GetStringBulider(number);
GetStringTime1(number);
GetStringBulider1(number);
}
/// <summary>
/// 測試string 性能時間
/// </summary>
private void GetStringTime(int number)
{
Stopwatch watch = new Stopwatch();
List< String> li = new List< string>();
watch.Start();
string str = "select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";
for (int i = 0; i < number; i++)
{
li.Add(str);
}
watch.Stop();
label1.Text = watch.ElapsedMilliseconds.ToString();
}
private void GetStringBulider(int number)
{
Stopwatch watch = new Stopwatch();
List<String> li = new List<string>();
watch.Start();
StringBuilder strb = new StringBuilder();
strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");
for (int i = 0; i < number; i++)
{
li.Add(strb.ToString());
}
watch.Stop();
label2.Text = watch.ElapsedMilliseconds.ToString();
}
/// <summary>
/// 測試string 性能時間變化
/// </summary>
private void GetStringTime1(int number)
{
Stopwatch watch = new Stopwatch();
List<String> li = new List<string>();
watch.Start();
string str = "select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";
for (int i = 0; i < number; i++)
{
str = str+"select * from testa inner join 快速排序耗費時間 快速排序耗費時間 快速排序耗費時間";
}
watch.Stop();
label1.Text =label1.Text+"不變,變化"+ watch.ElapsedMilliseconds.ToString();
}
/// <summary>
/// 測試stringBulider 變化的性能
/// </summary>
/// <param name="number"></param>
private void GetStringBulider1(int number)
{
Stopwatch watch = new Stopwatch();
List<String> li = new List<string>();
watch.Start();
StringBuilder strb = new StringBuilder();
strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");
for (int i = 0; i < number; i++)
{
strb.Append("select * from testa inner join dsadfasfsadfa快速排序耗費時間快速排序耗費時間");
}
watch.Stop();
label2.Text =label2.Text+"不變,變化"+ watch.ElapsedMilliseconds.ToString();
}
效果圖以下:
備註:每圖第一行表示string,第二行表示stringbulider,變化表示str++的意思或append。
四:總結:String 和stringbulider的總體彙總。
1. Sting是恆定的,string部裏的人是可變化的。
2. 對於簡單的字符串鏈接操做,在性能上stringbuilder不必定老是優於string。由於stringbulider對象的建立也消耗大量的性能,在字符串鏈接比較少的狀況下,過分濫用stringbuilder會致使性能的浪費而非節約,只有大量沒法預知次數的字符串操做才考慮stringbuilder的使用。從最後分析能夠看出若是是100行之內根本看不出太大差異。
3. Stringbulider的使用,最好制定合適的容量值,不然優於默認值容量不足而頻繁的進行內存分配操做,是不妥的實現方法。
能夠深思,第一咱們對適合的容量值處理了嗎? 第二,咱們是否是一再提要使用stringbuilder說性能好,可是在100行內的字符操做有分別嗎。
簡單的字符串鏈接操做能夠適度思考下 string.Concat 和 string.join 的使用。(string.concat的裝箱操做)。
參考文章:
http://www.cnblogs.com/juqiang/archive/2005/04/19/140538.html。
http://www.cnblogs.com/huangxincheng/p/4042105.html。
http://www.cnblogs.com/heartstill/archive/2011/11/11/2245411.html。
http://www.cnblogs.com/kid-li/archive/2006/10/18/532174.html。
http://www.cnblogs.com/gfwei/archive/2007/03/14/674499.html。
http://www.cnblogs.com/skychen1218/p/3593678.html。
書籍:《你必須知道的.net》什麼是string(345頁)。