最近面試深受打擊,我感到自己的內功不足。於是翻看了一下《java編程思想》,對多態有了更深的認識。
以前只知道多態有什么用,怎么用,但是不知道多態的原理是什么,現在大概是知道了,我也不想私藏,現與大家分享,老鳥就不用看了。
多態實現的原理就是“方法調用后期綁定”。
什么叫后期綁定?
講一個方法調用同一個方法主體關聯起來被稱作綁定。若在程序執行前進行綁定(例如編譯的時候)的話,叫做前期綁定(c語言都是前期綁定)。相應的,在運行時候根據對象的類型進行綁定叫后期綁定,也叫動態綁定。也就是說,如果一個語言想實現后期綁定,就必須具有某種機制,以便能夠在運行時能判斷對象的類型,從而調用恰當的方法。也就是說,編譯器一直不知道對象的類型,但是運行時方法調用機制能夠找到正確的方法體,並加以調用。不管怎樣,都必須在對象中安置某種類型信息。
在java中,除了static方法和final方法(private方法屬於final方法)之外,其他的都默認進行后期綁定(就是可以多態)。如果將一個方法聲明為final或者static或者private,就告訴編譯器不需要對該方法動態綁定。這樣,編譯器就可以可以為final方法調用生成更有效的代碼()。
總結一下:
1. java普通方法默認都是動態綁定的。
2. 父類static 和final方法(private除外),子類不可以重寫,編譯器會報錯。其中構造器默認是static的。
3. 父類private(也默認final的)方法,子類可以聲明同名方法(這個方法和父類同名方法只是名字相同,沒有什么關系),但是不會多態,也不可能多態,因為父類方法為private的。
4. 子類需要多態的方法的可視范圍(protected , public等)不能比父類的那個方法小(可以大),否則的話,父類可能沒法找到子類的那個方法,會編譯時報錯。
5. java的各種屬性不能多態。多態僅適用於方法。
下面看一個例子
1 class Base{ 2 3 public int a=2; 4 public void fmethod(){ 5 System.out.println("base:fmethod"); 6 } 7 int getA(){ 8 return a; 9 } 10 } 11 12 class Sub extends Base{ 13 public int a=3; 14 public void fmethod(){ //final表示不盡興多態 15 System.out.println("sub:fmethod"); 16 } 17 //子類方法可視范圍可以擴大 18 public int getA(){ 19 return a; 20 } 21 } 22 public class Test { 23 24 public static void main (String args []) { 25 Base b=new Sub(); 26 //方法多態,輸出sub:fmethod 27 b.fmethod(); 28 //屬性不能多態,輸出為2. 29 System.out.println(b.a); 30 //但是可以通過方法來實現屬性的多態,輸出3 31 System.out.println(b.getA()); 32 } 33 34 }
C#和java的多態機制大部分是一樣的,只是有一點,有着翻天覆地的不同。
不同:java普通方法默認是后期綁定的,而C#方法默認是前期綁定的,所以C#里面如果需要后期綁定(即多態),那么必須使用virtual + override+overide關鍵詞對。另一方面,好像重寫(這篇文章 所謂重寫 ,表示需要多態的用override修飾的)的方法訪問限制必須一致,不一致就報錯,不清楚這個說法對不對。
閑話少數,上代碼
1 class Base{ 2 3 public int a=2; 4 public void fmethod(){ 5 Console.WriteLine("base:fmethod"); 6 } 7 //virtual關鍵詞,可以提示編譯器這個方法可以被后面的子類重寫(子類方法需有override), 8 public virtual void gmethod() 9 { 10 Console.WriteLine("base:gmethod"); 11 } 12 13 public virtual void hmethod() 14 { 15 Console.WriteLine("base:hmethod"); 16 } 17 protected virtual int getA() 18 { 19 return a; 20 } 21 } 22 23 class Sub: Base 24 { 25 public int a=3; 26 //普通方法默認修飾符為new, public void fmethod = public new void fmethod 27 public void fmethod(){ 28 Console.WriteLine("sub:fmethod"); 29 } 30 //有override,與父類virtual 配對,多態 31 public override void gmethod() 32 { 33 Console.WriteLine("sub:gmethod"); 34 } 35 //即使父類方法有virual,子類方法沒有override,不會多態, 36 public void hmethod() 37 { 38 Console.WriteLine("sub:hmethod"); 39 } 40 41 42 //子類重寫的方法訪問限制必須一致,對不對? 43 protected override int getA(){ 44 return a; 45 } 46 } 47 48 class Subsub : Sub 49 { 50 //有override,與父類virtual 配對,多態 51 public override void gmethod() 52 { 53 Console.WriteLine("subsub:gmethod"); 54 } 55 public static void Main(String[] args) 56 { 57 Base b = new Sub(); 58 //輸出base:fmethod 59 b.fmethod(); 60 //輸出sub:gmethod 61 b.gmethod(); 62 //輸出base:hmethod 63 b.hmethod(); 64 //屬性不能多態,輸出為2. 65 Console.WriteLine(b.a); 66 Sub s = new Subsub(); 67 //輸出subsub:gmethod 68 s.gmethod(); 69 } 70 71 }
轉載請注明出處:博客園 stonehat http://www.cnblogs.com/stonehat/archive/2012/04/30/2476798.html