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

 

posted @ 2012-04-30 12:53  stonehat  阅读(2520)  评论(3编辑  收藏  举报