在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ 解析里氏替換原則,虛方法
解析接口
C#中一些易混淆概念總結(jié)-數(shù)據(jù)類(lèi)型存儲(chǔ)位置,方法調(diào)用,out和ref參數(shù)的使用
解析里氏替換原則,虛方法
繼承
構(gòu)造函數(shù),this關(guān)鍵字,部分類(lèi),枚舉
解析Console.WriteLine()
解析抽象類(lèi),抽象方法
結(jié)構(gòu),GC回收,靜態(tài)成員,靜態(tài)類(lèi)

解析里氏替換原則,虛方法

這一系列的文章在園子里還是比較受歡迎的。有一些留言指出了其中理論性的錯(cuò)誤,還有問(wèn)自己是否畢業(yè),怎么寫(xiě)出來(lái)這些文章的,有沒(méi)有培訓(xùn)過(guò)等等問(wèn)題。

下面就一并的回答這些問(wèn)題吧。
1)自己今年六月份畢業(yè),現(xiàn)在在帝都實(shí)習(xí)。不過(guò)在學(xué)校已經(jīng)做過(guò)一些C#開(kāi)發(fā)了,現(xiàn)在也是做.NET開(kāi)發(fā)工作。

2)文章中很多知識(shí)是自己以前在網(wǎng)上下載的視頻教程,學(xué)習(xí)過(guò)程中所記的筆記。也就是在年前的時(shí)候,突然有一天發(fā)現(xiàn)自己的筆記本記了差不多塊一本了,之前也沒(méi)時(shí)間整理過(guò),所以就想著把它們整理成博客文章,順便溫習(xí)一下這些筆記知識(shí)。

3)有園友問(wèn)自己是不是在傳智培訓(xùn)過(guò)。首先說(shuō)我沒(méi)有培訓(xùn)過(guò),但是非常感謝傳智公開(kāi)的一些自學(xué)教程。因?yàn)樽约阂彩沁@些視頻的受益者,學(xué)到了很多知識(shí),養(yǎng)成了一些好的學(xué)習(xí)習(xí)慣。

4)在整理筆記的過(guò)程中遇到了很多問(wèn)題,其中自己參考了《C#本質(zhì)論》,《CLR via C#》還有就是MSDN的官方文檔。

3)不管怎樣還是會(huì)遇到一些自己解決不掉或者弄不清楚的問(wèn)題,這個(gè)過(guò)程使用了Google搜索并和請(qǐng)教了一些園友。

4)錯(cuò)誤總是會(huì)存在。謝謝看我博客的讀者你們的細(xì)心,指出了我博文中的錯(cuò)誤。確定這些錯(cuò)誤后,我都立即修改了自己的文章。

今天開(kāi)始上班了。這幾天研究學(xué)習(xí)了一下思維導(dǎo)圖,感覺(jué)用它整理自己的知識(shí)非常的方便。所以,以后寫(xiě)博客完成一個(gè)知識(shí)點(diǎn),都會(huì)用思維導(dǎo)圖做一個(gè)總結(jié)。也能讓大家對(duì)所要讀的內(nèi)容有一個(gè)整體的把握。

我用的思維導(dǎo)圖軟件是FreeMind(免費(fèi)的,但是得裝JDK),因?yàn)閯傞_(kāi)始學(xué)習(xí)使用,很多操作技巧不是很熟練,做出來(lái)的導(dǎo)圖估計(jì)也不是很好,希望大家見(jiàn)諒。

首先,里氏替換原則。

這是理解多態(tài)所必須掌握的內(nèi)容。對(duì)于里氏替換原則維基百科給出的定義如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.1.png" alt="" />

為什么子類(lèi)可以替換父類(lèi)的位置,而程序的功能不受影響呢?

當(dāng)滿足繼承的時(shí)候,父類(lèi)肯定存在非私有成員,子類(lèi)肯定是得到了父類(lèi)的這些非私有成員(**假設(shè),父類(lèi)的的成員全部是私有的,那么子類(lèi)沒(méi)辦法從父類(lèi)繼承任何成員,也就不存在繼承的概念了)**。既然子類(lèi)繼承了父類(lèi)的這些非私有成員,那么父類(lèi)對(duì)象也就可以在子類(lèi)對(duì)象中調(diào)用這些非私有成員。所以,子類(lèi)對(duì)象可以替換父類(lèi)對(duì)象的位置。

來(lái)看下面的一段代碼:

 class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();

            Person p1 = new Student();

            Console.ReadKey();
        }
    }

    class Person
    {
    //父類(lèi)的私有成員
    private int nAge;

        public Person()
        {
            Console.WriteLine("我是Person構(gòu)造函數(shù),我是一個(gè)人!");
        }

        public void Say()
        {
            Console.WriteLine("我是一個(gè)人!");
        }

    }

    class Student : Person
    {
        public Student()
        {
            Console.WriteLine("我是Student構(gòu)造函數(shù),我是一個(gè)學(xué)生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一個(gè)學(xué)生!");
        }
    }

    class SeniorStudent : Student
    {
        public SeniorStudent()
        {
            Console.WriteLine("我是SeniorStudent構(gòu)造函數(shù),我是一個(gè)高中生!");
        }
        public  void SaySenior()
        {
            Console.WriteLine("我是一個(gè)高中生!");
        }
    }

我們運(yùn)行打印出的結(jié)果是:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.2.png" alt="" />

根據(jù)前面的構(gòu)造函數(shù)的知識(shí)很容易解釋這個(gè)結(jié)果。那么我們?cè)贛ain()函數(shù)中添加如下的代碼:

static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();
  
            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }

在訪問(wèn)的過(guò)程中,可以發(fā)現(xiàn)p只可以訪問(wèn)父類(lèi)的say

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.3.png" alt="" />

而p1也只可以訪問(wèn)父類(lèi)的Say方法

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.4.png" alt="" />

其實(shí)在上面的代碼中,就滿足了里氏替換原則。子類(lèi)的Student對(duì)象,替換了父類(lèi)Person對(duì)象的位置。

那么它們?cè)趦?nèi)存中發(fā)生了些什么呢?如下圖:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.5.png" alt="" />

由上可以知道,當(dāng)一個(gè)父類(lèi)的變量指向一個(gè)子類(lèi)對(duì)象的時(shí)候只能通過(guò)這個(gè)父類(lèi)變量調(diào)用父類(lèi)成員,子類(lèi)獨(dú)有的成員無(wú)法調(diào)用。

同理我們可以推理出,子類(lèi)的變量是不可以指向一個(gè)父類(lèi)的對(duì)像的

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.6.png" alt="" />

但是當(dāng)父類(lèi)變量指向一個(gè)子類(lèi)變量的時(shí)候,可以不可以把父類(lèi)的變量轉(zhuǎn)化成子類(lèi)的對(duì)象呢?看下圖

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.7.png" alt="" />

關(guān)于引用類(lèi)型的兩種轉(zhuǎn)換方式:

由上面的代碼我們已經(jīng)知道了一種轉(zhuǎn)換,就是在變量錢(qián)直接加需要轉(zhuǎn)換的類(lèi)型,如下代碼:

Student s2 = (Student)p1;

那么第二種轉(zhuǎn)換方式就是使用as關(guān)鍵字,如下代碼:

 //將指向子類(lèi)對(duì)象的變量轉(zhuǎn)化成子類(lèi)類(lèi)型
            Student s2 = (Student)p1;

            //使用as關(guān)鍵字,轉(zhuǎn)換失敗返回一個(gè)null值
            Student s3 = p1 as Student;

使用as關(guān)鍵字和第一種強(qiáng)制轉(zhuǎn)換的區(qū)別就是,第一種如果轉(zhuǎn)換失敗會(huì)拋異常,第二種轉(zhuǎn)換失敗則返回一個(gè)null值。

思維導(dǎo)圖總結(jié)如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.8.png" alt="" />

二,虛方法

使用virtual關(guān)鍵字修飾的方法,叫做虛方法(一般都是在父類(lèi)中)。

看下面的一段代碼:

class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person構(gòu)造函數(shù),我是一個(gè)人!");
        }

        //這里定義了一個(gè)虛方法
        public virtual void Say()
        {
            Console.WriteLine("我是一個(gè)人!");
        }

    }

    class Student : Person
    {
        //子類(lèi)使用override關(guān)鍵字改寫(xiě)了父類(lèi)的虛方法
        public override void Say()
        {
            Console.WriteLine("我是一個(gè)學(xué)生!");
        }
        public Student()
        {
            Console.WriteLine("我是Student構(gòu)造函數(shù),我是一個(gè)學(xué)生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一個(gè)學(xué)生!");
        }
    }

緊接著在main()函數(shù)中添加如下的代碼:

static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();

            Person p1 = new Student();
            p1.Say();

            Student s = new Student();
            s.Say();
            Console.ReadKey();
        }

打印結(jié)果如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.9.png" alt="" />

我們很明顯的可以發(fā)現(xiàn),第二個(gè)表達(dá)式滿足里氏替換原則,p1.Say()執(zhí)行的應(yīng)該是父類(lèi)的Say()方法,但是這里卻執(zhí)行了子類(lèi)的Say()方法。

這就是子類(lèi)使用override關(guān)鍵字的Say()方法覆蓋了父類(lèi)的用Virtual關(guān)鍵字修飾的Say()方法。

我們使用動(dòng)態(tài)圖片看一下調(diào)試過(guò)程,

①首先是沒(méi)有使用任何關(guān)鍵字:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.10.gif" alt="" />

由上可以看出直接跳入父類(lèi),執(zhí)行了父類(lèi)的Say()方法;

②再看使用virtual和override關(guān)鍵字的動(dòng)態(tài)調(diào)試圖片,如下

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.11.gif" alt="" />

可以看到直接到子類(lèi)去執(zhí)行override關(guān)鍵字修飾的Say()方法。

那么如果父類(lèi)使用virtual關(guān)鍵字修飾,而子類(lèi)沒(méi)有重寫(xiě)該方法時(shí)會(huì)怎么樣呢?如下面的代碼:

class Program
    {
        static void Main(string[] args)
        {

            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }
    }

    class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person構(gòu)造函數(shù),我是一個(gè)人!");
        }

        //這里定義了一個(gè)虛方法
        public virtual void Say()
        {
            Console.WriteLine("我是一個(gè)人!");
        }

    }

    class Student : Person
    {
        //子類(lèi)中沒(méi)有出現(xiàn)override關(guān)鍵字修飾的方法

        public void SayStude()
        {
            Console.WriteLine("我是一個(gè)學(xué)生!");
        }
    }

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

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.12.png" alt="" />

所以,如果子類(lèi)找不到override方法,則會(huì)回溯到該子類(lèi)的父類(lèi)去找是否有override方法,知道回溯到自身的虛方法,并執(zhí)行。

虛方法知識(shí)總結(jié)的思維導(dǎo)圖如下:

http://wiki.jikexueyuan.com/project/csharp-confusing-concepts-summary/images/6.13.png" alt="" />