前言
這一節主要來了解一下類和結構體之間的異同點、以及針對String和StringBuilder的用法、equals和==,其實可以看出很多地方都用到了上一節的值型別和引用型別、堆疊和裝箱拆箱操作吧,慢慢的應用於實踐,讓理論與實踐結合起來。
類和結構體
類和結構體的不同點:
1.關鍵字不同 一個是class,一個是struct
2.型別不同,一個是引用型別,一個是值型別(儲存:一個堆區,一個棧區)。關於值型別和引用型別以及堆與棧詳細可見http://www.cnblogs.com/aehyok/p/3504449.html
3.成員不同,結構體沒有預設的建構函式(可以新增)和沒有解構函式,不可以使用abstract,protected,sealed修飾
4.Struct變數使用完之後就自動解除記憶體分配,Class例項有垃圾回收機制來保證記憶體的回收處理
5.繼承性。結構不可以繼承自另一個結構或被繼承,但和類一樣可以繼承自介面
6.在結構體中可以宣告欄位,但是宣告欄位的時候是不能給初始值的.
7.實體類中如果我們沒有顯示的定義建構函式,那麼會有一個隱式無參的建構函式(過載建構函式之後,需要顯示宣告無參建構函式),
而在結構體中隱身無參的建構函式無論如何都存在
8.在類中可以顯示的定義無參的建構函式,而在結構體中我們不能顯示的定義無參的建構函式
9.結構體是可以New的,而結構體建構函式要求必須要為所有的欄位賦值.即使是無參的建構函式,也會給值型別賦初值為0,引用型別賦初值為null
同:
1.都有屬性和方法
2.和類一樣可以繼承自介面
String和StringBuilder
String 物件是不可改變的。每次使用 System.String 類中的方法之一時,都要在記憶體中建立一個新的字串物件,這就需要為該新物件分配新的空間。在需要對字串執行重複修改的情況下,與建立新的 String 物件相關的系統開銷可能會非常昂貴。如果要修改字串而不建立新的物件,則可以使用 System.Text.StringBuilder 類。例如,當在一個迴圈中將許多字串連線在一起時,使用 StringBuilder 類可以提升效能。
StringBuilder MyStringBuilder = new StringBuilder("Hello World!");
通過用一個過載的建構函式方法初始化變數,可以建立 StringBuilder 類的新例項,正如以下示例中所闡釋的那樣。
設定容量和長度
雖然 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.Format需要注意的一個效能問題http://www.cnblogs.com/dudu/archive/2012/05/29/string_format_stringbuilder.html
StringBuilder,String.concat(),String+String 哪一個效率高?http://q.cnblogs.com/q/36917/
equals和==
對於值型別,如果物件的值相等,則相等運算子 (==) 返回 true,否則返回 false。
對於string 以外的引用型別,如果兩個物件引用同一個物件,則 == 返回 true。對於 string 型別,== 比較字串的值。
==操作比較的是兩個變數的值是否相等。
equals()方法比較的是兩個物件的內容是否一致,equals也就是比較引用型別是否是對同一個物件的引用。
對於值型別的比較簡單,在此我們主要來看引用型別:
public class Person { public string Name { get; set; } public Person(string name) { this.Name = name; } } class Program { static void Main(string[] args) { string a = new string(new char[] { 'h', 'e', 'l', 'l', 'o' }); string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' }); Console.WriteLine(a == b); Console.WriteLine(a.Equals(b)); object g = a; object h = b; Console.WriteLine(g == h); Console.WriteLine(g.Equals(h)); Person p1 = new Person("aehyok"); Person p2 = new Person("aehyok"); Console.WriteLine(p1 == p2); Console.WriteLine(p1.Equals(p2)); Person p3 = new Person("aehyok"); Person p4 = p3; Console.WriteLine(p3 == p4); Console.WriteLine(p3.Equals(p4)); Console.ReadLine(); } }
結果輸出:
因為值型別是儲存在記憶體中的堆疊(以後簡稱棧),而引用型別的變數在棧中僅僅是儲存引用型別變數的地址,而其本身則儲存在堆中。
==操作比較的是兩個變數的值是否相等,對於引用型變數表示的是兩個變數在堆中儲存的地址是否相同,即棧中的內容是否相同。
equals操作表示的兩個變數是否是對同一個物件的引用,即堆中的內容是否相同。
而字串是一個特殊的引用型型別,在C#語言中,過載了string 物件的很多方法方法(包括equals()方法),使string物件用起來就像是值型別一樣。
因此在上面的例子中,字串a和字串b的兩個比較是相等的。
而g.equals(h)用的是sting的equals()方法故相等(多型)。如果將字串a和b作這樣的修改:
string a="aa";
string b="aa";
則,g和h的兩個比較都是相等的。這是因為系統並沒有給字串b分配記憶體,只是將"aa"指向了b。所以a和b指向的是同一個字串(字串在這種賦值的情況下做了記憶體的優化)。
對於p1和p2,也是記憶體中兩個不同的物件,所以在記憶體中的地址肯定不相同,故p1==p2會返回false,又因為p1和p2又是對不同物件的引用,所以p1.equals(p2)將返回false。
對於p3和p4,p4=p3,p3將對物件的引用賦給了p4,p3和p4是對同一個物件的引用,所以兩個比較都返回true。