java/C#多态漫谈
最近面试深受打击,我感到自己的内功不足。于是翻看了一下《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