久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      C# 中的多態(tài)性

      相信大家都對面向?qū)ο蟮娜齻€(gè)特征封裝、繼承、多態(tài)很熟悉,每個(gè)人都能說上一兩句,但是大多數(shù)都僅僅是知道這些是什么,不知道 CLR 內(nèi)部是如何實(shí)現(xiàn)的,所以本篇文章主要說說多態(tài)性中的一些概念已經(jīng)內(nèi)部實(shí)現(xiàn)的機(jī)理。

      一、多態(tài)的概念

      首先解釋下什么叫多態(tài):同一操作作用于不同的對象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果,這就是多態(tài)性。換句話說,實(shí)際上就是同一個(gè)類型的實(shí)例調(diào)用”相同”的方法,產(chǎn)生的結(jié)果是不同的。這里的”相同”打上雙引號是因?yàn)檫@里的相同的方法僅僅是看上去相同的方法,實(shí)際上它們調(diào)用的方法是不同的。

      說到多態(tài),我們不能免俗的提到下面幾個(gè)概念:重載、重寫、虛方法、抽象方法以及隱藏方法。下面就來一一介紹他們的概念。

      1、重載(overload): 在同一個(gè)作用域(一般指一個(gè)類)的兩個(gè)或多個(gè)方法函數(shù)名相同,參數(shù)列表不同的方法叫做重載,它們有三個(gè)特點(diǎn)(俗稱兩必須一可以):

      • 方法名必須相同
      • 參數(shù)列表必須不相同
      • 返回值類型可以不相同

      例如:

      public void Sleep()  {      Console.WriteLine("Animal睡覺");  }  public int Sleep(int time)  {      Console.WriteLine("Animal{0}點(diǎn)睡覺", time);      return time;  }

      2、重寫(override):子類中為滿足自己的需要來重復(fù)定義某個(gè)方法的不同實(shí)現(xiàn),需要用 override 關(guān)鍵字,被重寫的方法必須是虛方法,用的是 virtual 關(guān)鍵字。它的特點(diǎn)是(三個(gè)相同):

      • 相同的方法名
      • 相同的參數(shù)列表
      • 相同的返回值

      如:父類中的定義:

      public virtual void EatFood()  {      Console.WriteLine("Animal吃東西");  }

      子類中的定義:

      public override void EatFood()  {      Console.WriteLine("Cat吃東西");      //base.EatFood();  }

      小提示:經(jīng)常有童鞋問重載和重寫的區(qū)別,而且網(wǎng)絡(luò)上把這兩個(gè)的區(qū)別作為 C# 做??嫉拿嬖囶}之一。實(shí)際上這兩個(gè)概念完全沒有關(guān)系,僅僅都帶有一個(gè)”重”字。他們沒有在一起比較的意義,僅僅分辨它們不同的定義就好了。

      3、虛方法:即為基類中定義的允許在派生類中重寫的方法,使用virtual關(guān)鍵字定義。如:

      public virtual void EatFood()  {      Console.WriteLine("Animal吃東西");  }

      注意:虛方法也可以被直接調(diào)用。如:

      Animal a = new Animal();  a.EatFood();

      執(zhí)行輸出結(jié)果為:

      Animal吃東西

      4、抽象方法:在基類中定義的并且必須在派生類中重寫的方法,使用 abstract 關(guān)鍵字定義。如:

      public abstract class Biology  {      public abstract void Live();  }  public class Animal : Biology  {      public override void Live()      {          Console.WriteLine("Animal重寫的抽象方法");          //throw new NotImplementedException();      }   }

      注意:抽象方法只能在抽象類中定義,如果不在抽象類中定義,則會報(bào)出如下錯(cuò)誤:

      C# 中的多態(tài)性

      虛方法和抽象方法的區(qū)別是:因?yàn)槌橄箢悷o法實(shí)例化,所以抽象方法沒有辦法被調(diào)用,也就是說抽象方法永遠(yuǎn)不可能被實(shí)現(xiàn)。

      5、隱藏方法:在派生類中定義的和基類中的某個(gè)方法同名的方法,使用 new 關(guān)鍵字定義。如在基類 Animal 中有一方法 Sleep():

      public void Sleep()  {      Console.WriteLine("Animal Sleep");  }

      則在派生類 Cat 中定義隱藏方法的代碼為:

      new public void Sleep()  {      Console.WriteLine("Cat Sleep");  }

      或者為:

      public new void Sleep()  {      Console.WriteLine("Cat Sleep");  } 

      注意:

      • (1)隱藏方法不但可以隱藏基類中的虛方法,而且也可以隱藏基類中的非虛方法。
      • (2)隱藏方法中父類的實(shí)例調(diào)用父類的方法,子類的實(shí)例調(diào)用子類的方法。
      • (3)和上一條對比:重寫方法中子類的變量調(diào)用子類重寫的方法,父類的變量要看這個(gè)父類引用的是子類的實(shí)例還是本身的實(shí)例,如果引用的是父類的實(shí)例那么調(diào)用基類的方法,如果引用的是派生類的實(shí)例則調(diào)用派生類的方法。

      好了,基本概念講完了,下面來看一個(gè)例子,首先我們新建幾個(gè)類:

      public abstract class Biology  {      public abstract void Live();  }  public class Animal : Biology  {      public override void Live()      {          Console.WriteLine("Animal重寫的Live");          //throw new NotImplementedException();      }      public void Sleep()      {          Console.WriteLine("Animal Sleep");      }      public int Sleep(int time)      {          Console.WriteLine("Animal在{0}點(diǎn)Sleep", time);          return time;      }      public virtual void EatFood()      {          Console.WriteLine("Animal EatFood");      }  }  public class Cat : Animal  {      public override void EatFood()      {          Console.WriteLine("Cat EatFood");          //base.EatFood();      }      new public void Sleep()      {          Console.WriteLine("Cat Sleep");      }      //public new void Sleep()      //{      //    Console.WriteLine("Cat Sleep");      //}  }  public class Dog : Animal  {      public override void EatFood()      {          Console.WriteLine("Dog EatFood");          //base.EatFood();      }  }

      下面來看看需要執(zhí)行的代碼:

      class Program  {      static void Main(string[] args)      {          //Animal的實(shí)例          Animal a = new Animal();          //Animal的實(shí)例,引用派生類Cat對象          Animal ac = new Cat();          //Animal的實(shí)例,引用派生類Dog對象          Animal ad = new Dog();          //Cat的實(shí)例          Cat c = new Cat();          //Dog的實(shí)例          Dog d = new Dog();          //重載          a.Sleep();          a.Sleep(23);          //重寫和虛方法          a.EatFood();          ac.EatFood();          ad.EatFood();          //抽象方法          a.Live();          //隱藏方法          a.Sleep();          ac.Sleep();          c.Sleep();          Console.ReadKey();      }  }

      首先,我們定義了幾個(gè)我們需要使用的類的實(shí)例,需要注意的是:

      • (1)Biology類是抽象類,無法實(shí)例化;
      • (2)變量ac是Animal的實(shí)例,但是指向一個(gè)Cat的對象。因?yàn)镃at類型是Animal類型的派生類,所以這種轉(zhuǎn)換沒有問題。這也是多態(tài)性的重點(diǎn)。

      下面我們來一步一步的分析:

      1、

      //重載  a.Sleep();  a.Sleep(23);

      很明顯,Animal 的變量 a 調(diào)用的兩個(gè) Sleep 方法是重載的方法,第一句調(diào)用的是無參數(shù)的 Sleep() 方法,第二句調(diào)用的是有一個(gè) int 參數(shù)的 Sleep 方法。注意兩個(gè) Sleep 方法的返回值不一樣,這也說明了重寫的三個(gè)特征中的最后一個(gè)特征——返回值可以不相同。

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

      Animal Sleep  Animal在23點(diǎn)Sleep

      2、

      //重寫和虛方法  a.EatFood();  ac.EatFood();  ad.EatFood();

      在這一段中,a、ac 以及 ad 都是 Animal 的實(shí)例,但是他們引用的對象不同,a 引用的是 Animal 對象,ac 引用的是 Cat 對象,ad 引用的是 Dog 對象,這個(gè)差別會造成執(zhí)行結(jié)果的什么差別呢,請看執(zhí)行結(jié)果:

      Animal EatFood  Cat EatFood  Dog EatFood

      第一句 Animal 實(shí)例,直接調(diào)用 Animal 的虛方法 EatFood,沒有任何問題。

      在第二、三句中,雖然同樣是 Animal 的實(shí)例,但是他們分別指向 Cat 和 Dog 對象,所以調(diào)用的 Cat 類和 Dog 類中各自重寫的 EatFood 方法,就像是 Cat 實(shí)例和 Dog 實(shí)例直接調(diào)用 EatFood 方法一樣。這個(gè)也就是多態(tài)性的體現(xiàn):同一操作作用于不同的對象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果。

      3、

      //抽象方法  a.Live();

      這個(gè)比較簡單,就是直接重寫父類 Biology 中的 Live 方法,執(zhí)行結(jié)果如下:

      Animal重寫的Live

      4、

      //隱藏方法  a.Sleep();  ac.Sleep();  c.Sleep();

      在分析隱藏方法時(shí)要和虛方法、重寫相互比較。變量 a 調(diào)用 Animal 類的 Sleep 方法以及變量 c 調(diào)用 Cat 類的 Sleep 方法沒有異議,但是變量 ac 引用的是一個(gè) Cat 類型的對象,它應(yīng)該調(diào)用 Animal 類型的 EatFood 方法呢,還是 Cat 類型的 EatFood 方法呢?答案是調(diào)用父類即 Animal 的 EatFood 方法。執(zhí)行結(jié)果如下:

      Animal Sleep  Animal Sleep  Cat Sleep

      大多數(shù)的文章都是介紹到這里為止,僅僅是讓我們知道這些概念以及調(diào)用的方法,而沒有說明為什么會這樣。下面我們就來深入一點(diǎn),談?wù)劧鄳B(tài)背后的機(jī)理。


      二、深入理解多態(tài)性

      要深入理解多態(tài)性,就要先從值類型和引用類型說起。我們都知道值類型是保存在線程棧上的,而引用類型是保存在托管堆中的。因?yàn)樗械念惗际且妙愋?,所以我們僅僅看引用類型。

      現(xiàn)在回到剛才的例子,Main 函數(shù)時(shí)程序的入口,在 JIT 編譯器將 Main 函數(shù)編譯為本地CPU指定時(shí),發(fā)現(xiàn)該方法引用了 Biology、Animal、Cat、Dog這幾個(gè)類,所以 CLR 會創(chuàng)建幾個(gè)實(shí)例來表示這幾個(gè)類型本身,我們把它稱之為”類型對象”。該對象包含了類中的靜態(tài)字段,以及包含類中所有方法的方法表,還包含了托管堆中所有對象都要有的兩個(gè)額外的成員——類型對象指針(Type Object Point)和同步塊索引(sync Block Index)。

      可能上面這段對于有些沒有看過相關(guān)CLR書籍的童鞋沒有看懂,所以我們畫個(gè)圖來描述一下:

      C# 中的多態(tài)性

      上面的這個(gè)圖是在執(zhí)行 Main 函數(shù)之前 CLR 所做的事情,下面開始執(zhí)行 Main 函數(shù)(方便起見,簡化一下 Main 函數(shù)):

      //Animal的實(shí)例  Animal a = new Animal();  //Animal的實(shí)例,引用派生類Cat對象  Animal ac = new Cat();  //Animal的實(shí)例,引用派生類Dog對象  Animal ad = new Dog();  a.Sleep();  a.EatFood();  ac.EatFood();  ad.EatFood();

      下面實(shí)例化三個(gè) Animal 實(shí)例,但是他們實(shí)際上指向的分別是 Animal 對象、Cat 對象和 Dog 對象,如下圖:

      C# 中的多態(tài)性

      請注意,變量 ac 和 ad 雖然都是 Animal 類型,但是指向的分別是 Cat 對象和 Dog 對象,這里是關(guān)鍵。

      當(dāng)執(zhí)行 a.Sleep() 時(shí),由于 Sleep 是非虛實(shí)例方法,JIT 編譯器會找到發(fā)出調(diào)用的那個(gè)變量(a)的類型(Animal)對應(yīng)的類型對象(Animal 類型對象)。然后調(diào)用該類型對象中的 Sleep 方法,如果該類型對象沒有 Sleep 方法,JIT 編譯器會回溯類的基類(一直到 Object)中查找 Sleep 方法。

      當(dāng)執(zhí)行 ac.EatFood 時(shí),由于 EatFood 是虛實(shí)例方法,JIT 編譯器調(diào)用時(shí)會在方法中生成一些額外的代碼,這些代碼會首先檢查發(fā)出調(diào)用的變量(ac),然后跟隨變量的引用地址找到發(fā)出調(diào)用的對象(Cat 對象),找到發(fā)出調(diào)用的對象對應(yīng)的類型對象(Cat 類型對象),最后在該類型對象中查找 EatFood 方法。同樣的,如果在該類型對象中沒有查找到 EatFood 方法,JIT 編譯器會回溯到該類型對象的基類中查找。

      上面描述的就是 JIT 編譯器在遇到調(diào)用類型的非虛實(shí)例方法以及虛實(shí)例方法時(shí)的不同執(zhí)行方式,也這是處理這兩類方法的不同方式造成了表面上我們看到的面向?qū)ο蟮娜齻€(gè)特征之一——多態(tài)性。

      原文地址:https://www.cnblogs.com/zhangkai2237/archive/2012/12/20/2826734.html

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號