好久沒寫文章了,再拿起這本書,學習加分享,樂趣無窮啊。這兩天看了寫關於字串的知識,從學寫代碼的時候開始,我們就基本天天跟String打交道,對它再熟悉不過了。但是仔細看看,還是有一種撥開雲霧的感覺,對平日裡的一些問題頓然明白了。
一、 string執行個體化
1. 建立string對象
string str1 = "hello world."; //√
string str2 = new string("hello world"); //×
按照錯誤提示試一下char[]型別參數發現可以的:
string str2 = new string(new char[] { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' });//√
2.IL代碼
string str1=”hello world”; 對應的IL代碼為:
我們知道執行個體化參考型別時對應的IL代碼為newobj,但是通過我們發現string類型比較特殊,使用的ldstr(load string)指令來構建對象。
3. 幾點說明:
- String 直接繼承自System.Object,它是參考型別,其執行個體儲存在堆上。而且string是密封類,它是不能夠被繼承的。
- 換行:提倡使用Envionment.NewLine進行換行而不是逸出字元,因為NewLine會根據平台返回相應的字元,及時跨平台也能正常運行。
- @符號:檔案路徑或者Regex中出現斜線時,為了防止誤當做逸出字元,可以在字串前添加@。例如@"D:\CLRviaC#\Demo01"。
- string和System.String:System.String是.net framework中定義的一個類型,string是C#定義的一個關鍵字,代表System.String這種類型,可認為是System.String的簡寫形式。之前一直認為它是基元類型,經IsPrimitive方法驗證其實並不是。(多謝Fish Li指正)。
- ToString()方法:基類System.Object中包含了該方法,一般在具體使用時會重新定義該類。這個方法比較熟悉,就不贅述了。
二、 字串駐留
1. 字串的特色之一就是恒定不變,對於字串的任何操作(如SubString,ToUpper等)其實都是產生了一個新的字串,原字串是保留不變的。
我們來看個例子來驗證一下是不是這樣的:
//①
string str1 = "HelloWorld";
string str2 = "HelloWorld";
Console.WriteLine(ReferenceEquals(str1, str2));
//②
string str3 = "Hello" + "World";
Console.WriteLine(ReferenceEquals(str1, str3));
//③
string str4 = "Hello";
string str5 = "World";
string str6 = str4 + str5;
Console.WriteLine(ReferenceEquals(str1, str6));
//④
str6 = string.Intern(str6);
Console.WriteLine(ReferenceEquals(str1, str6));
運行結果跟之前的預測或許會有些出入,這是因為CLR使用了字串駐留的技術,它是通過建立一個雜湊表來實現的,其中Key是字串,value是對於託管堆中string對象的引用,每當建立新的字串執行個體的時候會先檢測雜湊表中是否已經存在相同的字串。
具體到上面例子中:
- ①根據字串駐留技術,str1和str2字串內容完全相同,實際上指向了同一個引用;
- ②用+串連的字串文本常量str3,在編譯期間就已經完成串連動作,所以str3也和str1指向了同一引用;
- ③str6是在運行時才將str4和str5串連在一起的,這個過程中建立了多個字串對象,最終str6和str1指向的不是同一個引用。
- ④調用了String.Intern(string str)方法(下文介紹),強制使用字串駐留技術,所以str6和str1指向了同一引用。
2. String類兩個訪問雜湊表的方法:
- Public static string Intern(string str);
擷取string類型對象的雜湊碼,並在雜湊表中檢查是否有匹配項,如果存在則返回string對象的引用,如果不存在,則將其副本添加到雜湊表中然後返回引用。
- Public static string IsInterned(string str);
與上面的方法類似,不同的是沒有匹配項時會返回Null,而不會自動將字串添加到雜湊表中。
3. 駐留雖有用,使用需謹慎
當有大量的字串操作時,駐留機制確實能夠節省記憶體,但是我們卻不能濫用這個機制。寫程式的時候不能一直預設該機制的存在,除非我們顯式調用String.Intern方法,避免產生意想不到的錯誤,因為這個機制其實是可以被編譯器禁用的,隨著.NET版本的變化,不能保證一直預設啟用字串駐留。而且,字串駐留機制對效能和記憶體的提高也不是絕對的,因為字串駐留的過程本身也是需要時間的。總之,使用的時候還是要謹慎一些。
三、 StringBuilder
String類型字串是恒定不變的,當進行字串累加等大量的字串操作時,會佔用大量的記憶體。此時最好使用System.Text.StringBuilder類型。
1. 構造StringBuilder對象
StringBuilder使用new關鍵字構造對象,不像String類型那樣特殊。它有大概6種構造器,主要是用來分配和初始化StringBuilder對象的狀態,主要包括:
- 字串最大容量,預設是Int32.MaxValue;
- 字元數組:char結構構成的數組,負責維護字串中的字元內容;
- 容量:指定StringBuilder維護的字元數組的長度,預設為16.當容量不足時,會自動倍增。
2.與String類型配合
StringBuilder可以通過ToString()方法在堆上建立相應的String對象,其中包含了該時刻在StringBuilder中的字串內容。還可以通過Append()方法等將字串再次添加到StringBuilder中。
StringBuilder提供的方法與String不是完全對應的,可以巧妙的利用它們配合完成一些字串操作。其中ToLower,Trim,EndsWith等方法是String具有的,而Replace等方法又是StringBuilder特有的。
例如:
StringBuilder s = new StringBuilder();
s.AppendFormat("{0} {1}", "Cathy", "Chen").Replace(" ","-");
string s1 = s.ToString().ToUpper();
Console.WriteLine(s1);
你也許喜歡:跟小靜讀CLR via C#(00)-開篇及目錄