類:
類是引用類型在堆上分配,類的實例進行賦值只是複製了引用,都指向同一段實際對象分配的內存
類有構造和析構函數
類能夠繼承和被繼承
結構:
結構是值類型在棧上分配(雖然棧的訪問速度比較堆要快,但棧的資源有限放),結構的賦值將分配產生一個新的對象。
結構沒有構造函數,但能夠添加。結構沒有析構函數
結構不能夠繼承自另外一個結構或被繼承,但和類同樣能夠繼承自接口
結構體和類一樣可以定義字段,方法和構造函數,都能實例化對象,這樣看來結構體和類的功能好像是同樣的了,可是他們在數據的存儲上是不同的(如下摘錄):
C#結構體和類的區別問題:在C#編程語言中,類屬於引用類型的數據類型,結構體屬於值類型的數據類型,這兩種數據類型的本質區別主要是各自指向的內存位置不一樣。傳遞類的時候,主要表現爲是否同時改變了源對象。
C#結構體和類的區別技術要點:
◆類在傳遞的時候,傳遞的內容是位於託管內存中的位置,結構體在傳遞的時候,傳遞的內容是位於程序堆棧區的內容。當類的傳遞對象修改時,將同時修改源對象,而結構體的傳遞對象修改時,不會對源對象產生影響。
◆在一個類中,能夠定義默認的、不帶參數的構造函數,而在結構體中不能定義默認的、不帶參數的構造函數。二者均可以定義帶有參數的構造函數,經過這些參數給各自的字段賦值或初始化
代碼運行以下:類中賦值之後,兩個對象中的值都發生變化,而結構體原來對象的值爲發生變化編程
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 類對象 { //枚舉 public enum Gender { 男, 女 } //結構體 public struct stuPerson { public string stuName; public int stuAge; public Gender stuSex; public void stuSayHello() { Console.WriteLine("我是{0},年齡{1},性別{2}", stuName, stuAge, stuSex); } //必須定義有參數的構造函數 public stuPerson(string name, int age, Gender sex) { this.stuName = name; this.stuAge = age; this.stuSex = sex; } } class Program { static void Main(string[] args) { //實例化類 Person Liuxiang = new Person(); //無參數的構造函數實例化的對象 Liuxiang.Name = "劉翔"; Liuxiang.Age = 30; Liuxiang.Sex = Gender.男; Liuxiang.SayHello(); //聲明另外一個實例 Person LXSon = Liuxiang; LXSon.Age = 10; //查看類 LiuXiang 和 LXSon中字段的值 Console.WriteLine("LiuXiang 年齡{0}", Liuxiang.Age.ToString()); //10 Console.WriteLine("LXSon 年齡{0}", LXSon.Age.ToString()); //10 Console.WriteLine(); //結構體 stuPerson YaoMing = new stuPerson("姚明",33,Gender.男); YaoMing.stuSayHello(); stuPerson YMSon = YaoMing; YMSon.stuAge = 13; //查看結構體中 YaoMing 和 YMSon中字段的值 Console.WriteLine("YaoMing 年齡{0}", YaoMing.stuAge.ToString()); //10 Console.WriteLine("YMSon 年齡{0}", YMSon.stuAge.ToString()); //10 Console.ReadLine(); } } class Person { //定義字段 public string Name; public int Age; public Gender Sex; //定義方法 public void SayHello() { Console.WriteLine("我是{0},年齡{1},性別{2}", this.Name, this.Age, this.Sex); } //無參數的構造函數 public Person() { } //有參數的構造函數 public Person(string name, int age, Gender sex) { this.Name = name; this.Age = age; this.Sex = sex; } } }
總結起來,二者共有以下區別:
一、結構是值類型,類則是引用類型。所以前者是放在棧(Stack)裏,後者則僅僅是將引用地址存放在棧裏,而具體的值則存放在堆(heap)裏。以下圖所示:
二、據第1點能夠得出結論,那就是類對象一般用來傳遞大數據,而結構對象則用來傳遞小數據。
三、類能夠被繼承,而結構則不支持。
四、結構對象不能像類對象同樣賦值爲null。
五、結構不能像類同樣定義析構器。
六、結構不能像類同樣定義爲抽象的。
七、在結構中不能重寫方法,除非是object類型的以下方法:安全
若要讓結構具備多態特性,可讓其實現接口。
八、在類中定義的事件是線程安全的,而結構則不是。
九、結構老是具備一個默認的公共無參構造函數,但去不能像類同樣定義私有的無參構造函數: 併發
struct Me { private Me() // compile-time error { } } class Me { private Me() // runs Ok{ }
十、類中的靜態構造函數會被調用,而結構卻不能。所以在結構中定義的靜態構造函數,雖然能夠編譯經過,但卻沒有價值: app
struct myStructure { static myStructure() { Console.WriteLine("This is me a structure"); } } class myClass { static myClass() { Console.WriteLine("This is me a class"); } } class Program { static void Main(string[] args) { myStructure s = new myStructure();//Nothing happen myClass c = new myClass();//Will out put This is me a class Console.Read(); } }
十一、結構不能像類同樣定義volatile字段。volatile字段主要用於併發,它至關於方法體的lock。編程語言
十二、能夠對結構類型使用sizeof,對類則不行。
1三、類的字段會被自動初始化爲0/false/null,而結構則不能。
1四、在結構中不能直接對字段初始化,而類則能夠。 函數
struct myStructure { public string x = 2;//Not allowed } class myClass { public string x = 2; //Allowed }
1五、結構和類對於System.Object.Equals()方法的體現是不相同的。例如定義這樣的結構和類: 大數據
struct StructurePerson { public string FirstName; public string LastName; } class ClassPerson { public string FirstName; public string LastName; }
若是運行以下的代碼: ui
class Program { static void Main(string[] args) { StructurePerson strX = new StructurePerson(); strX.LastName = "Bejaoui"; strX.FirstName = "Bechir"; StructurePerson strY = new StructurePerson(); strY.LastName = "Bejaoui"; strY.FirstName = "Bechir"; if (strX.Equals(strY)) { Console.WriteLine("strX = strY"); } else { Console.WriteLine("strX != strY"); }//This code displays strX = strY ClassPerson clsX = new ClassPerson(); clsX.LastName = "Bejaoui"; clsX.FirstName = "Bechir"; ClassPerson clsY = new ClassPerson(); clsY.LastName = "Bejaoui"; clsY.FirstName = "Bechir"; if (clsX.Equals(clsY)) { Console.WriteLine("clsX = clsY"); } else { Console.WriteLine("clsX != clsY"); }//This code displays clsX != clsY Console.Read(); } }
ClassPerson clsX = new ClassPerson(); clsX.LastName = "Bejaoui"; clsX.FirstName = "Bechir"; ClassPerson clsY = clsX; if (clsX.Equals(clsY)) { Console.WriteLine("clsX = clsY"); } else { Console.WriteLine("clsX != clsY"); }//This codedisplays clsX = clsY
因爲是直接將clsX賦值給clsY,所以兩個對象的引用地址相等,Equals()方法返回true。
其實對於值類型和引用類型的相等性比較,是一個比較複雜的問題。例如咱們能夠經過重寫Equals()方法加強或修改比較邏輯。重寫Equals()方法還必須重寫GetHashCode()方法。對於引用類型,還可使用靜態方法ReferenceEquals()方法。此外,還能夠重載操做符==。另外,對於String對象,則比較特殊,由於它使用了Immutable模式。雖然String類型是引用類型,但若是直接定義的兩個String對象的值相同,因爲採用了Immutable模式的緣由,這兩個對象實際上是同一個對象,引用地址是相同的。所以不只動態方法Equals()返回的是true,且靜態方法ReferenceEquals()返回的也是truethis