深入理解Java中的多态机制

在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征
 

引言:

多态通过分离做什么和怎么做,从另一个角度将接口和实现分离开来。多态不但能够改善代码的组织结构和可读性,还能够创建可扩展的程序--即无论在项目最初创建时还是在需要时添加新功能时都可以“生长”的程序。

 

本文目录大纲:

一、什么是多态

二、多态的类别

三、多态的产生方式

四、运行期多态必要条件

五、向上转型

六、向下转型

七、动态多态的适用范围

八、多态的好处

 

 

1、什么是多态

多态(Polymorphism),按字面的意思就是“多种状态”。简单而通俗的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

 

2、多态的类别

编译期多态(静态多态,早期绑定)和运行期多态(后期绑定);

 

绑定:将一个方法调用同一个方法主体关联起来被称做绑定。

 

前期绑定:在程序执行前绑定(由编译器和连接程序实现),称作前期绑定。它是面向过程的语言中不需要选择就默认的绑定方式。列入C只有一种方法调用,那就是前期绑定。

 

后期绑定:在运行时根据对象的类型进行绑定。后期绑定也称作动态绑定或运行时绑定。它通过某种特殊机制实现,即程序一直不知道对象的类型,但是方法调用机制调用机制能找到正确的方法体,并加以调用。

 

Java中除了static 方法和final 方法(private 属于final 方法)之外,其他所有方法都是后期绑定。这意味着通常情况下,我们不必判定是否应该进行后期绑定--它会自动发生。

 

3、多态产生的方式

 

3.1、强制的:一种隐式做类型转换的方法。

 

        强制多态隐式的将参数按某种方法,转换成编译器认为正确的类型以避免错误。在一下的表达式中,编译器必须决定二元运算符‘+’所应做的工作:        

[java] view plain copy

1.  int a = 1 + 2;  

2.  double d = 2.0 + 2.0;  

3.  String s = "abc" + "def";  

跟据需要判定"+ " 运算符所要进行的运算,(1和(2行中进行加法运算,(3中进行字符串连接运算

 

3.2、编译期多态(重载  overload):

 

静态多态性:包括变量的隐藏、方法的重载(指同一个类中,方法名相同(方便记忆),但是方法的参数类型、个数、次序不同,本质上是多个不同的方法);

举例:

 

[java] view plain copy
 
 print?
  1. public class override{  
  2.       public void show( ){  
  3.       };  
  4.       public void show( int i){  
  5.            System.out.println("含参数的show方法 .");  
  6.       };  
  7. }  



 

通过传入不同参数,让程序根据传入的参数来表现出不同的状态。进而实现多态。

 

3.3、运行期多态(重写 override)

 

动态多态性:是指子类在继承父类(或实现接口)时重写了父类(或接口)的方法,程序中用父类(或接口)引用去指向子类的具体实例,从代码形式上看是父类(或接口)引用去调用父类(接口)的方法,但是在实际运行时,JVM能够根据父类(或接口)引用所指的具体子类,去调用对应子类的方法,从而表现为不同子类对象有多种不同的形态。不过,程序代码在编译时还不能确定调用的哪一个类的方法,只有在运行时才能确定,故又称为运行时的多态性。

 

举例:

 

[java] view plain copy
 
 print?
  1. public classsup {  
  2.    public void show(){  
  3.       System.out.println("show() in sup !");  
  4.    }  
  5. }  
  6. public classsub extendssup{  
  7.    public void show(){  
  8.       System.out.println("show() in sub !");  
  9.    }  
  10. }  
  11. public classClient {  
  12.    
  13.    public static void main(String[] args) {  
  14.        
  15.       supsp= new sup();  
  16.       subsb = new sub();  
  17.       sups = new sub();  
  18.        
  19.       sp.show();  
  20.       sb.show();  
  21.       s.show();  
  22.    }  
  23. }  



 

运行结果:

show() in sup !

show() in sub !

show() in sub !

 

第三行代码,虽然编译是sup类,但运行的却是sub的show()方法。通过方法的重载,让程序表现出不同的状态,来体现程序的多态性。

 

4、运行期多态必要条件

一、要有继承(包括接口的实现);
二、要有重写;
三、父类引用指向子类对象。

 

5、向上转型

          子类自有的方法不可见

         1)、代码检查不允许。

         2)、从实际意义上

 

在下面代码中,s只能调用sup中曾声明过的方法,而子类中新增加的所独有的方法则并不可见,自然也无法调用。

 

sup s = new sub();

s.show();

 

 

6、向下转型

          存在于继承中,父类引用指向的对象实际是要转型的子类引用的类型。

 

假设现在已经定义一个了Animal类,并且定义类Dog和类Cat继承Animal.

 

[java] view plain copy

1.  1)  Animal a = new Dog();  

2.    

3.        Dog d = (Dog) a;    //正确  

4.    

5.  2) Animal a = new Cat();  

6.    

7.        Dog d = (Dog) a;    //抛异常    

 

对于一个由向上转型而来的对象,如果对它实行向下转型,需要知道该对象之前的类型。否则编译器会报错。如上述代码所描述一样。

 

7、动态多态的适用范围

 

1、只适用于动态方法,对于变量不能被重写(覆盖),”重写“的概念只针对方法,如 变量不能被重写(覆盖)

2、静态static方法属于特殊情况,域不会有多态机制。所调用的方法根据编译时采用的类型所确定。

 

下面通过代码解释:

 

[java] view plain copy
 
 print?
  1. /* 
  2. 样例1: 
  3.   classParent{ 
  4.      int num = 3; 
  5.   } 
  6.   
  7.   classChild extends Parent{ 
  8.      int num = 4; 
  9.   } 
  10. */  
  11.    
  12. /* 
  13. 样例2: 
  14. class Parent{ 
  15.   
  16.   
  17. class Child extends Parent{ 
  18.     intnum = 4; 
  19. */  
  20.    
  21. /* 
  22. 样例3: 
  23. class Parent{ 
  24.     void show(){ 
  25.         System.out.println("ParentShow!"); 
  26.      } 
  27.   } 
  28.   
  29.   classChild extends Parent{ 
  30.     void show(){ 
  31.         System.out.println("ChildShow!"); 
  32.      } 
  33.   } 
  34. */  
  35.    
  36. /* 
  37. 样例4: 
  38. class Parent{ 
  39.      
  40.   } 
  41.   
  42.   class Child extends Parent{ 
  43.     voidshow(){ 
  44.         System.out.println("ChildShow!"); 
  45.      } 
  46.   } 
  47. */  
  48.    
  49.    
  50. class Parent{  
  51.     static void show(){  
  52.         System.out.println("ParentShow!");  
  53.      }  
  54.   }  
  55.    
  56.   class Child extends Parent{  
  57.     static void show(){  
  58.         System.out.println("ChildShow!");  
  59.      }  
  60.   }  
  61.    
  62.    
  63. public class PC{  
  64.    public static void main(String[] args){  
  65.         Parentp = new Child();  
  66.         //样例1:  
  67.         //System.out.println(p.num);//3, 输出的是父类的num;  
  68.            
  69.         //样例2:  
  70.         //System.out.println(p.num);//错误: 找不到符号 num  
  71.            
  72.         //样例3:  
  73.         //p.show();//ChildShow!  输出的是子类的方法!  
  74.            
  75.         //样例4:  
  76.         //p.show();//  错误: 找不到符号   p.show();  
  77.            
  78.         //样例5:  
  79.         p.show();//Parent Show!  运行父类的静态方法。  
  80.    }   
  81. }  
  82.    
  83. /*  



 

总结:

对象多态时:

1.成员变量:(不涉及覆盖)

编译时: 参考引用变量所属的类中是否有调用的成员变量,有, 编译通过,没有,编译失败。

运行时: 参考引用变量所属的类中是否有调用的成员变量, 并运行该类所属中的成员变量。

简单的说:编译和运行都参考等号的左边。

 

2.成员函数(非静态):

编译时:参考引用变量所属的类中是否有调用的成员变量, 有, 编译通过, 没有,编译失败:

运行时:参考的是对象所属的类中是否有调用的函数。

简单的说:编译看左边, 运行看右边。

 

3.静态函数, 变量:

   编译和运行都是参考左边参数类型!

   其实静态方法不存在多态, 静态方法是属于类的,我们说的是对象的多态!静态方法直接用类名调用就好了,

   没必要创建对象!

   静态的方法只能被静态的方法所覆盖!

 

8、多态的好处

 

1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

 

2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

 

3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。

 

4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

 

5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

 

 

参考资料:http://www.cnblogs.com/hujunzheng/p/3872619.html

 

原文地址:http://blog.csdn.net/qq_25184739/article/details/51141738

posted on 2016-04-21 23:52  小小事件不爱我  阅读(92)  评论(0)    收藏  举报