.NET中類和結構的區別


類:
類是引用類型在堆上分配,類的實例進行賦值只是復制了引用,都指向同一段實際對象分配的內存
類有構造和析構函數
類可以繼承和被繼承
結構:
結構是值類型在棧上分配(雖然棧的訪問速度比較堆要快,但棧的資源有限放),結構的賦值將分配產生一個新的對象。
結構沒有構造函數,但可以添加。結構沒有析構函數
結構不可以繼承自另一個結構或被繼承,但和類一樣可以繼承自接口

結構體和類同樣能夠定義字段,方法和構造函數,都能實例化對象,這樣看來結構體和類的功能好像是一樣的了,但是他們在數據的存儲上是不一樣的(以下摘錄):
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;
        }
    }
}

總結起來,兩者共有如下區別:
1、結構是值類型,類則是引用類型。因此前者是放在棧(Stack)里,后者則僅僅是將引用地址存放在棧里,而具體的值則存放在堆(heap)里。如下圖所示:
 
2、據第1點可以得出結論,那就是類對象通常用來傳遞大數據,而結構對象則用來傳遞小數據。
3、類可以被繼承,而結構則不支持。
4、結構對象不能像類對象一樣賦值為null。
5、結構不能像類一樣定義析構器。
6、結構不能像類一樣定義為抽象的。
7、在結構中不能重寫方法,除非是object類型的如下方法:

  1. Equals()
  2. GetHashCode()   
  3. GetType()    
  4. ToString()

若要讓結構具有多態特性,可以讓其實現接口。
8、在類中定義的事件是線程安全的,而結構則不是。
9、結構總是具有一個默認的公共無參構造函數,但去不能像類一樣定義私有的無參構造函數:
   

   struct Me
    {
        private Me() // compile-time error
        {
        }
    }
    
    class Me
    {
        private Me() // runs Ok{
    }

 

10、類中的靜態構造函數會被調用,而結構卻不能。因此在結構中定義的靜態構造函數,雖然可以編譯通過,但卻沒有價值:    

    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();
        }
    }

11、結構不能像類一樣定義volatile字段。volatile字段主要用於並發,它相當於方法體的lock。

12、可以對結構類型使用sizeof,對類則不行。
13、類的字段會被自動初始化為0/false/null,而結構則不能。
14、在結構中不能直接對字段初始化,而類則可以。
  

    struct myStructure
    {
        public string x = 2;//Not allowed
    }
    class myClass
    {
        public string x = 2; //Allowed
    }

15、結構和類對於System.Object.Equals()方法的體現是不相同的。例如定義這樣的結構和類:  

     struct StructurePerson
    {
        public string FirstName;
        public string LastName;
    }
    class ClassPerson
    {
        public string FirstName;
        public string LastName;
    }

如果運行如下的代碼:   

    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();
        }
    }
由於結構類型是值類型,因而Equals()方法比較的是兩個對象的值是否相等,如果相等則返回true;而類類型為引用類型,Equals()方法比較的是二者的引用地址(即指針)是否相等。很顯然,clsX和clsY是兩個不同的對象,它們在棧的地址是不相等的。如果修改代碼如下:  
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()返回的也是true


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM