溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

發(fā)布時(shí)間:2020-07-25 09:34:51 來(lái)源:網(wǎng)絡(luò) 閱讀:1875 作者:yisuowushinian 欄目:編程語(yǔ)言

目錄:

【C#小知識(shí)】C#中一些易混淆概念總結(jié)

【C#小知識(shí)】C#中一些易混淆概念總結(jié)(二)

---------------------------------------分割線----------------------------------------------

一,C#中結(jié)構(gòu)

在C#中可以使用struct關(guān)鍵字來(lái)定義一個(gè)結(jié)構(gòu),級(jí)別與類是一致的,寫在命名空間下面。

1)結(jié)構(gòu)中可以定義屬性,字段,方法和構(gòu)造函數(shù)。示例代碼如下:

//定義結(jié)構(gòu)
    struct Point
    {
                                                                                       
        //定義字段
        private int x;
        //封裝字段
        public int X
        {
            get { return x; }
            set { x = value; }
        }
                                                                                        
        //定義方法
        public void Result()
        {
                                                                                            
        }
        //定義構(gòu)造函數(shù)
        public Point(int n)
        {
            this.x = n;
            //Console.WriteLine(n);
        }
    }


那么,聲明類與結(jié)構(gòu)的區(qū)別有哪些呢?

無(wú)論如何,C#編譯器都會(huì)為結(jié)構(gòu)生成無(wú)參數(shù)的構(gòu)造函數(shù);

當(dāng)我們顯式的定義無(wú)參數(shù)的構(gòu)造函數(shù),編譯時(shí)會(huì)報(bào)錯(cuò),結(jié)果如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

編譯器告訴我們,結(jié)構(gòu)不能包含顯式的無(wú)參數(shù)的構(gòu)造函數(shù)

但是這樣編寫代碼時(shí),編譯器卻不報(bào)錯(cuò),代碼如下:

//這里可以調(diào)用無(wú)參數(shù)的構(gòu)造函數(shù)

Point p = new Point();            

Console.WriteLine(p.GetType());

運(yùn)行結(jié)果如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

雖然結(jié)構(gòu)不能顯式的聲明無(wú)參數(shù)的構(gòu)造函數(shù),但是程序員卻可以顯式的調(diào)用結(jié)構(gòu)的無(wú)參數(shù)的構(gòu)造函數(shù),說(shuō)明C#編譯器無(wú)論如何都會(huì)為結(jié)構(gòu)生成無(wú)參數(shù)的構(gòu)造函數(shù)。

②結(jié)構(gòu)中的字段不能賦初始值;

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

③在結(jié)構(gòu)的構(gòu)造函數(shù)中必須要對(duì)結(jié)構(gòu)體的每一個(gè)字段賦值;

當(dāng)我們不聲明顯式的構(gòu)造函數(shù)時(shí),可以不對(duì)成員字段賦值,但是一旦聲明了構(gòu)造函數(shù),就要對(duì)所有的成員字段賦值

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

對(duì)所有的成員字段賦值,代碼如下:

     //定義構(gòu)造函數(shù)

public Point(int n)        

{            

   this.x = n;            

   //Console.WriteLine(n);

}

④在構(gòu)造函數(shù)中對(duì)屬性賦值不認(rèn)為對(duì)字段賦值,屬性不一定去操作字段;

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

所以在構(gòu)造函數(shù)中我們對(duì)字段賦初始值的時(shí)候,正確的代碼應(yīng)該是

//定義構(gòu)造函數(shù)
        public Point(int n)
        {
            //正確的可以對(duì)字段賦初始值
            this.x = n;
            //在構(gòu)造函數(shù)中對(duì)屬性賦值,但是不一定操作字段
            this.X = n;
            //Console.WriteLine(n);
        }


2)結(jié)構(gòu)體的數(shù)值類型問(wèn)題

C#中的結(jié)構(gòu)是值類型,它的對(duì)象和成員字段是分配在棧中的,如下圖:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

那么當(dāng)我們寫了如下的代碼,內(nèi)存中發(fā)生了什么呢?

//這里可以調(diào)用無(wú)參數(shù)的構(gòu)造函數(shù)
          Point p = new Point();
          //為p的屬性賦值
          p.X = 100;
          //將p賦值給Point新的對(duì)象p1
          Point p1 = p;


Point p1=p發(fā)生了什么呢?情況如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

聲明結(jié)構(gòu)體對(duì)象可以不使用“new”關(guān)鍵字如果不使用“new”關(guān)鍵字聲明結(jié)構(gòu)體對(duì)象,因?yàn)闆](méi)有調(diào)用構(gòu)造函數(shù),這個(gè)時(shí)候結(jié)構(gòu)體對(duì)象是沒(méi)有值的。而結(jié)構(gòu)的構(gòu)造函數(shù)必須為結(jié)構(gòu)的所有字段賦值,所以通過(guò)"new"關(guān)鍵字創(chuàng)建結(jié)構(gòu)體對(duì)象的時(shí)候,這個(gè)對(duì)象被構(gòu)造函數(shù)初始化就有默認(rèn)的初始值了。實(shí)例代碼如下

class Program
    {
        static void Main(string[] args)
        {
           //沒(méi)有辦法調(diào)用默認(rèn)的構(gòu)造函初始化
            Point p;
            Console.WriteLine(p);
            //會(huì)調(diào)用默認(rèn)的構(gòu)造函數(shù)對(duì)的Point對(duì)象初始化
            Point p1 = new Point();
            Console.WriteLine(p1);
            Console.ReadKey();
        }
    }
    //定義結(jié)構(gòu)
    struct Point
    {
        //定義時(shí)賦初始值,編譯器會(huì)報(bào)錯(cuò)
        private int x;
    }


編譯的時(shí)候會(huì)報(bào)錯(cuò):

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


3)結(jié)構(gòu)體不能使用自動(dòng)屬性

在第一篇文章我寫自動(dòng)屬性的時(shí)候,反編譯源代碼,知道自動(dòng)屬性,會(huì)生成一個(gè)默認(rèn)字段。而在結(jié)構(gòu)的構(gòu)造函數(shù)中需要對(duì)每一個(gè)字段賦值,但是編譯器不知道這個(gè)字段的名字。所以,沒(méi)有辦法使用自動(dòng)屬性。


那么什么時(shí)候定義類,什么時(shí)候定義結(jié)構(gòu)體呢?

首先我們都知道的是,棧的訪問(wèn)速度相對(duì)于堆是比較快的。但是棧的空間相對(duì)于堆來(lái)說(shuō)是比較小的。

①當(dāng)我們要表示一個(gè)輕量級(jí)的對(duì)象,就可以定義結(jié)構(gòu)體,提高訪問(wèn)速度。

②根據(jù)傳值的影響來(lái)選擇,當(dāng)要傳遞的引用就定義類,當(dāng)要傳遞的是“拷貝”就定義結(jié)構(gòu)體。

二,關(guān)于GC(.NET的垃圾回收)

1)分配在棧中的空間變量,一旦出了該變量的作用域就會(huì)被CLR立即回收;如下代碼:

//定義值類型的n當(dāng),程序出了main函數(shù)后n在棧中占用的空間就會(huì)被CLR立即回收
        static void Main(string[] args)
        {
            int n = 5;
            Console.WriteLine(n);
        }

2)分配在堆里面的對(duì)象,當(dāng)沒(méi)有任何變量的引用時(shí),這個(gè)對(duì)象就會(huì)被標(biāo)記為垃圾對(duì)象,等待垃圾回收器的回收;

GC會(huì)定時(shí)清理堆空間中的垃圾對(duì)象,這個(gè)時(shí)間頻率是程序員無(wú)法控制的,是由CLR決定的。所以,當(dāng)一個(gè)對(duì)象被標(biāo)記為垃圾對(duì)象的時(shí)候,不一定會(huì)被立即回收。

3)析構(gòu)函數(shù)

在回收垃圾對(duì)象的時(shí)候,析構(gòu)函數(shù)被GC自動(dòng)調(diào)用。主要是執(zhí)行一些清理善后工作。

析構(gòu)函數(shù)沒(méi)有訪問(wèn)修飾符,不能有你參數(shù),使用“~”來(lái)修飾。 如下面的代碼示例:

class Program
    {
        //定義值類型的n當(dāng),程序出了main函數(shù)后n在棧中占用的空間就會(huì)被CLR立即回收
        static void Main(string[] args)
        {
            int n = 5;
            OperateFile operate = new OperateFile();
            operate.FileWrite();
            //執(zhí)行完寫操作后,會(huì)調(diào)用該類的析構(gòu)函數(shù),釋放對(duì)文件對(duì)象的控制
            //Console.WriteLine(n);
        }
    }
    //定義操作硬盤上文件上的類
    class OperateFile
    {
        //定義寫文件的方法
        public void FileWrite()
        { }
        //定義調(diào)用該類結(jié)束后,所要執(zhí)行的動(dòng)作
        ~OperateFile()
        {
        //釋放對(duì)操作文件對(duì)象的控制
        }
    }


三,靜態(tài)成員和實(shí)例成員的區(qū)別:

靜態(tài)成員是需要通過(guò)static關(guān)鍵字來(lái)修飾的,而實(shí)例成員不用static關(guān)鍵字修飾。他們區(qū)別如下代碼:

class Program
    {
        static void Main(string[] args)
        {
            //靜態(tài)成員屬于類,可以直接通過(guò)“類名.靜態(tài)成員”的方式訪問(wèn)
            Person.Run();
            //實(shí)例成員屬于對(duì)象,需要通過(guò)“對(duì)象名.實(shí)例成員”來(lái)訪問(wèn)
            Person p = new Person();
            p.Sing();
        }
    }
    class Person
    {
        //靜態(tài)成員變量
        private static int nAge;
        //實(shí)例成員變量
        private string strName;
        public static void Run()
        {
            Console.WriteLine("我會(huì)奔跑!");
        }
        public void Sing()
        {
            Console.WriteLine("我會(huì)唱歌");
        }
    }

當(dāng)類第一次被加載的時(shí)候(就是該類第一次被加載到內(nèi)存當(dāng)中),該類下面的所有靜態(tài)的成員都會(huì)被加載。實(shí)例成員有多少對(duì)象,就會(huì)創(chuàng)建多少對(duì)象。

而靜態(tài)成員只被加載到靜態(tài)存儲(chǔ)區(qū),只被創(chuàng)建一次,且直到程序退出時(shí)才會(huì)被釋放。

看下面的代碼:

class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            Person p1 = new Person();
            Person p2 = new Person();
        }
    }
                                      
    class Person
    {
        //靜態(tài)成員變量
        private static int nAge;
        //實(shí)例成員變量
        private string strName;
        public static void Run()
        {
            Console.WriteLine("我會(huì)奔跑!");
        }
        public void Sing()
        {
            Console.WriteLine("我會(huì)唱歌");
        }
    }

那么在內(nèi)存中發(fā)生了什么呢?如下圖:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


由上面顯然可知,定義靜態(tài)的成員是可以影響程序的執(zhí)行效率的。那么什么時(shí)候定義靜態(tài)的成員變量呢?

①變量需要被共享的時(shí)候②方法需要被反復(fù)的調(diào)用的時(shí)候

2)在靜態(tài)方法中不能直接調(diào)用實(shí)例成員。

當(dāng)類第一次被加載的時(shí)候,靜態(tài)成員已經(jīng)被加載到靜態(tài)存儲(chǔ)區(qū),此時(shí)類的對(duì)象還有可能能沒(méi)有創(chuàng)建,所以靜態(tài)方法中不能調(diào)用類成員字段。實(shí)例代碼如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


this和base關(guān)鍵字都不能在靜態(tài)方法中使用。

②可以創(chuàng)建類的對(duì)象指明對(duì)象的成員在靜態(tài)方法中操作,代碼如下:

public static void Run()
       {
           Person p = new Person();
           p.strName = "強(qiáng)子";
           Console.WriteLine("我會(huì)奔跑!");
       }

③在實(shí)例成員中肯定可以調(diào)用靜態(tài)方法,因?yàn)檫@個(gè)時(shí)候靜態(tài)成員肯定存在,代碼如下:

public static void Run()
        {
            Person p = new Person();
            p.strName = "強(qiáng)子";
            Console.WriteLine("我會(huì)奔跑!");
        }
        public void Sing()
        {
            //實(shí)例方法被調(diào)用的時(shí)候,對(duì)象實(shí)例一定會(huì)被創(chuàng)建,所以可以在實(shí)例方法中訪問(wèn)實(shí)例的字段
            this.strName = "子強(qiáng)";
            strName = "子強(qiáng)";
            //調(diào)用靜態(tài)成員
            Run();
            Console.WriteLine("我會(huì)唱歌");
        }

靜態(tài)成員和實(shí)例成員的對(duì)比:

①生命周期不一樣

靜態(tài)成員只有在程序結(jié)束時(shí)才會(huì)釋放,而實(shí)例成員沒(méi)有對(duì)象引用時(shí)就會(huì)釋放

②內(nèi)存中存儲(chǔ)的位置不一樣

靜態(tài)成員存放在靜態(tài)存儲(chǔ)區(qū),實(shí)例成員在托管堆中。


四,靜態(tài)類

①靜態(tài)類被static關(guān)鍵字修飾

//定義兩個(gè)靜態(tài)類

staticclass Person    { }  

internalstaticclass Cat    { }


②靜態(tài)類中只能生命靜態(tài)的成員變量,否則會(huì)報(bào)錯(cuò)(因?yàn)樵L問(wèn)該實(shí)例成員的時(shí)候,類的對(duì)象可能還沒(méi)有被創(chuàng)建

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類

③靜態(tài)類中不能有實(shí)例的構(gòu)造函數(shù)(如果有實(shí)例的構(gòu)造函數(shù),則該靜態(tài)類能被實(shí)例化,都是靜態(tài)成員,沒(méi)有實(shí)例成員被調(diào)用

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


正確的聲明方法:

static class Person
    {
        //private int nAge;
        private static string strName;
        static Person()
        {
        }
    }


④靜態(tài)類不能被繼承,反編譯剛才的兩個(gè)類,結(jié)果如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


會(huì)發(fā)現(xiàn)靜態(tài)類的本質(zhì)是一個(gè)抽象密封類,所以不能被繼承和實(shí)例化。所以,靜態(tài)類的構(gòu)造函數(shù),不能有訪問(wèn)修飾符


2)那么什么時(shí)候聲明靜態(tài)類呢?

如果這個(gè)類下面的所有成員的都需要被共享,可以把這個(gè)類聲明為靜態(tài)類。

且在一般對(duì)象中不能聲明靜態(tài)類型的變量(訪問(wèn)該靜態(tài)變量時(shí),可能該對(duì)象還沒(méi)有被創(chuàng)建)。

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


3)靜態(tài)類的構(gòu)造函數(shù)

靜態(tài)類可以有靜態(tài)的構(gòu)造函數(shù)(且所有類都可以有靜態(tài)的構(gòu)造函數(shù)),如下代碼:

class Program
    {
        static void Main(string[] args)
        {
            Cat c;
            Cat c1 = new Cat();
            Console.ReadKey();
        }
    }
    class Cat
    {
        private int n;
        public string strName;
        //實(shí)例構(gòu)造函數(shù)
        public Cat()
        {
            Console.WriteLine("看誰(shuí)先執(zhí)行2");
        }
        //靜態(tài)構(gòu)造函數(shù)
        static Cat()
        {
            Console.WriteLine("看誰(shuí)先執(zhí)行1");
        }
    }

執(zhí)行結(jié)果如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


由此我們可以知道,靜態(tài)的構(gòu)造函數(shù)會(huì)先于實(shí)例構(gòu)造函數(shù)執(zhí)行

//不執(zhí)行靜態(tài)構(gòu)造函數(shù)

Cat c;

當(dāng)我們?cè)贛ain()函數(shù)中添加如下的代碼是:

static void Main(string[] args)
        {
            //不執(zhí)行靜態(tài)構(gòu)造函數(shù)
            Cat c;
            Cat c1 = new Cat();
            Cat c2 = new Cat();
            Console.ReadKey();
        }

運(yùn)行結(jié)果如下:

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


說(shuō)明靜態(tài)的構(gòu)造函數(shù)只執(zhí)行了一次。

---------------------------------------------分割線-----------------------------------------------


好吧這次的分享風(fēng)到此結(jié)束。希望對(duì)大家對(duì)理解C#基礎(chǔ)概念知識(shí)能有所幫助。


如果您覺(jué)得不錯(cuò),點(diǎn)擊右下角贊一下吧!您的支持,是我寫作的動(dòng)力!

畢業(yè)實(shí)習(xí)交流群:221376964。你也可以關(guān)注我的新浪微博進(jìn)行交流。

C#中一些易混淆概念總結(jié)(三)--------結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI