Java中的多态的简单总结

来源:互联网 发布:linux 停止iscsi服务 编辑:程序博客网 时间:2024/05/09 23:32

       时间在流逝,春节也快要到了。别的同学都已经在家好多天,自己还在学校继续忙着。要想人前显贵,就得人后受罪,依然记得高中的时候物理老师送给我们的话,虽然有时候感觉很寂寞,但是想想现在的付出是为了以后的美好生活,还是会很有动力。

今天总结面向对象设计中的多态(polymorphism)了,刚开始接触多态这个概念的时候觉得很混乱,随着学习的不断深入,渐渐开始理解这种机制。

  1. 多态的概念
  2. 多态的实现机制
  3. final关键字

一、多态的概念

       从字面上理解,多态可以理解为多种形态,多种类型。我们知道,通过继承可以使用父类型(supertype)来引用子类型变量(subtype),也就是说,每个子类对象也可以看做是超类的对象,在程序中可以将多种类型(从同一基类导出的类型)视为同一类型来处理。而同一段代码也就可以毫无差别的运行在不同类型之上了。这些,就是实现多态机制的基础。一个对象变量可以引用多种实际类型的现象被称之为多态

来看一段代码:

import java.util.*;/** * This program demonstrates inheritance. * @version 1.21 2013/01/25 * @author LiMing */public class ManagerTest{   public static void main(String[] args)   {      // construct a Manager object      Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);      boss.setBonus(5000);      Employee[] staff = new Employee[3];      // fill the staff array with Manager and Employee objects      staff[0] = boss;      staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);      staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);      // print out information about all Employee objects      for (Employee e : staff)         System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());   }}class Employee{   public Employee(String n, double s, int year, int month, int day)   {      name = n;      salary = s;      GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);      hireDay = calendar.getTime();   }   public String getName()   {      return name;   }   public double getSalary()   {      return salary;   }   public Date getHireDay()   {      return hireDay;   }   public void raiseSalary(double byPercent)   {      double raise = salary * byPercent / 100;      salary += raise;   }   private String name;   private double salary;   private Date hireDay;}class Manager extends Employee{   /**    * @param n the employee's name    * @param s the salary    * @param year the hire year    * @param month the hire month    * @param day the hire day    */   public Manager(String n, double s, int year, int month, int day)   {      super(n, s, year, month, day);      bonus = 0;   }   public double getSalary()   {      double baseSalary = super.getSalary();      return baseSalary + bonus;   }   public void setBonus(double b)   {      bonus = b;   }   private double bonus;}

        我们可以想象,一个经理Manager必然是一个雇员Employee,经理是子类型,而雇员是父类型。在代码中我们通过

staff[0]=boss; 这条语句将Manager型的引用赋给了Employee类型,在Employee类中拥有一个方法getSalary(),而在Manager中有同样的一个方法getSalary(),程序运行的最后结果我们惊奇的发现,Employee型的对象引用竟然正确的调用了我们希望的Manager的getSalary方法。这个例子作为多态的简单演示,下面我们来讨论多态的实现机制。

二、多态的实现机制

       首先我们先了解几个术语:绑定(binding),《Java编程思想》中说“将一个方法调用同一个方法主体关联起来被称作绑定”

这句话个人理解是这样的:假设集合A是一个由所有类中的所有的方法组成的方法集合,集合B是由全部的对象以及每个对象所拥有

的动作(方法)组成的集合,当我们程序在出现方法调用的时候,必然是由集合B和集合A中的两个元素进行交互。B中的一个元素调

用A中的方法时,通过一个过程来找到确定的该调用的方法,这个过程被称之为绑定。
在程序执行之前进行的绑定被称之为前期绑定(静态绑定)这是由编译器以及连接程序确定的(至于前期绑定的具体过程还请高手不

吝赐教),在程序运行过程中实现的绑定被称之为后期绑定(动态绑定、运行时绑定)。在Java中所有的方法都是通过动态绑定来实

现多态的
     我们主要来研究动态绑定这个概念,首先我们需要区分变量的实际类型(actual type)与声明类型(declared type),我们

知道一个变量必须要被声明为某种类型。请看下面这两句代码:

Employee obj = new Manager();obj.getSalary();

这里obj的声明类型是Employee,一个引用变量可以是一个null值或者是一个对声明类型实例的引用。实例可以是该类型本身或者它

的子类型。变量的实际类型是被变量引用的对象的实际类。在这里obj引用的是Manager类型的变量,所以obj的声明类型是Employee

,实际类型是Manager。当调用getSalary方法时是由obj的实际类型所决定的,因为在程序运行之前我们并不能够确定某个变量将引

用何种类型,所以需要在运行时加以确定,从而调用相应的方法,这就是动态绑定。

 

我们来看看动态绑定的工作机制:
   1>编译器查看对象的声明类型以及方法名。假设调用obj.function(param),且隐式参数obj被声明为C类的对象(C类作为子类来看

待)。需要注意的是:有可能存在多个名字为funciton的,但参数类型不一样的方法。例如可能存在function(int),function

(String)等。编译器会列举C类中的所有名为function的方法和其超类中访问属性为public的且名为function的方法。至此编译器

已经获得了所有可能被调用的候选方法。
   2>接下来编译器将查看调用方法时提供的类型参数。如果所有名为function的方法中存在一个与提供的类型参数完全匹配,就选

择这个方法。这个过程被称之为重载解析(overloading resolution)
总之,当程序运行时并且采用动态绑定调用方法时,虚拟机一定调用与obj所引用的对象的实际类型最适合的那个类的方法。假设

obj的实际类型是A,需要调用function(int)型的方法,它是B类的子类,如果A类定义了function(int)方法,就直接调用它;

否则在A类的超类中寻找function(int),以此类推。
我们来看一段代码:

public class DynamicBinding {/** * 演示动态绑定 * @author LiMing * @since 2013/01/25 * @param args */public static void main(String[] args) {// TODO Auto-generated method stubPerson[] p =new Person[3];p[0]=new Person();p[1]=new Student();p[2]=new GraduateStudent();for(Person obj:p)printObject(obj);}public static void printObject(Object o){System.out.println(o.toString());}}class Person{public Person(){}public String toString(){return "This is class Person!";}}class Student extends Person{public Student(){}public String toString(){return "This is class Student!";}}class GraduateStudent extends Student{public GraduateStudent(){}public String toString(){return "This is calss GraduateStudent!";}}

匹配方法的签名和绑定的方法的实现是两个独立的事情。引用变量的声明类型决定了编译时匹配哪个方法。编译器在编译时,会根据类型参数、参数个数和参数顺序找到匹配的方法。一个方法可能在几个子类中都被实现。Java虚拟机在运行是动态绑定的方法的实现,这是由变量的实际类型决定的。

 

 


 

 

原创粉丝点击