Java多态

来源:互联网 发布:知识产权 淘宝 编辑:程序博客网 时间:2024/04/26 18:32

多态性(polymorphism)是一个希腊词汇,意思为“多种形式(many forms)”。在面向对象编程中,继承层次机构内的超类以及一个或多个子类定义具有相同方法时会出现多态性。

在下列条件下,运行时系统会执行子类方法:

1.子类对象被指派给超类引用变量

2.方法调用使用超类引用变量

 

在继承层次结构中,程序能够将任何子类对象指派给一个超类引用变量,这个指派操作设置超类引用指向子类对象。例如

Employee emp;

SalaryEmployee sEmp(“Morris, Mike”,”569-34-0382”,1250.00);

emp = sEmp; // 指派操作设置Employee变量指向SalaryEmployee对象Mike Morris

或者 Employeeemp = new SalaryEmployee(“Morris, Mike”,”569-34-0382”,1250.00);

将子类对象指派给超类变量会影响与超类引用关联的方法所调用的作用域和动作。

分两种情况

第一种,超类没有定义这个方法,而子类定义了这个方法

超类变量可以用于调用只在超类中定义的任何公用方法,不过它不能调用只在子类中定义的方法。例如 SalaryEmployee继承Employee类

Employee emp;可以使用setName()方法来修改SalaryEmployee对象sEmp的名字,但不能使用setSalary()方法,这是因为该方法只在子类中定义。所以emp不能访问setSalary()方法。

编译器分析语句emp.setName()和sEmp.setSalary()时会标识变量的引用类型和方法之间的关联关系。这样,变量调用相应类中的某个公用方法。编译器使用了一个名为静态绑定(static binding) 的功能,静态绑定将方法与引用变量的类类型关联在一起。术语“静态”表明编译器在执行前建立了一个关联关系。

注释:借助于静态绑定,方法调用与特定类在编译时被关联在一起。

自己的理解:其实 静态绑定 就是类自己调用自己的方法,而不会指向其他继承类的方法

第二种,超类和子类具有相同的方法时,情况是不一样的。假定子类方法重写超类方法,使用超类引用变量调用这种类型的方法会应用到多态性,并且运行时系统会执行子类对象中的方法。

与使用将方法与超类引用变量关联在一起的静态绑定不一样的是,编译器会指导运行时系统确定变量引用的超类类型,随后还会调用相应的子类方法。因为引用变量与方法之间的关联关系在运行期间建立,所以这被称为动态绑定 (dynamic binding)。

注释:使用动态绑定调用某个方法时,运行时系统会确定引用变量指向的对象的类型,并且为这个对象调用该方法。

例如:方法pay多态性为公司员工创建了工资单

首先定义一个pay方法

public static void pay(String dateRange,Employee emp)

{

System.out.println(“Payperiod:”+dateRange);

System.out.println(emp.payrollCheck());

}

SalaryEmployee sEmp = new SalaryEmployee(“Bonner,Al”,”667-21-7128”,1500.00);

pay(“July 3 to July 9”,sEmp);

Employee是父类,SalaryEmployee是它的子类,父类子类均有payrollCheck()方法,而pay()方法不属于它们中的任何一类,而是通过pay()方法调用

首先我们定义了一个SalaryEmployee类对象并使用构造函数进行初始化,我们把引用变量作为实参传递给pay()方法中,主要相当于

emp = sEmp; 或者全写出来

Employee emp = new SalaryEmployee(“Bonner,Al”,”667-21-7128”,1500.00);

实现多态,这样可以 重复使用pay()方法,增加代码的重用效率。

 

向上与向下转型

 

程序可以使用超类变量引用子类对象,在子类对象被指派给超类变量时就会出现这样的引用。因为这个处理将位于继承层次结构底层(子类)的一个对象与高层(超类)的一个引用关联在一起,所以我们将其称为向上转型(upcasting。即超类引用变量可以调用超类中的任何公共方法,也可以调用应用了多态性的子类中的任何公用方法。

注释:使用超类变量引用子类对象时就会出现向上转型。

 

还有一种情况是:

如果想要调用子类中有而父类中没有的方法,需要进行向下强制类型转换

编程人员必须通过转型将变量引用类型显式地更改为子类的引用类型。这种转型的语法类似于原始变量的转型。子类名被放入圆括号内,随后立即使超类引用变量。我们将这个处理称为向下转型(downcasting,例如

倘若将Employee引用变量emp转型为一个SalaryEmployee引用,那么我们就可以将emp与方法setSalary()一起使用。(setSalary()方法只在子类SalaryEmployee里面定义,而没有在超类Employee定义)。

((SalaryEmployee)emp).setSalary(2400.00);//通过括号()规定优先级,先把emp转换成SalaryEmployee类,再调用SalaryEmployee的setSalary()方法。

 

instanceof操作符

只要向下转型改变了一个超类引用变量的引用类型,这个引用变量就能用来调用子类方法。在一个程序中,我们需要处理子类类型只在运行时已知的情况。虽然不能预定义转型的选择,但是一旦标识出子类类型就必须选择转型。例如,假定某个应用程序定义了为员工指定加薪比例的静态方法payIncrease(),这个方法既不是父类的方法也不是子类的方法而是应用程序定义的新方法且将一个Employee引用变量作为参数,该参数允许程序将SalaryEmployee和HourlyEmployee对象作为实参进行传递。

public void payInstance(Employee emp,double pct)

{

}

注释:如果x是一个引用,CL是一个类,那么使用instanceof操作符能够确定x是否引用了CL。编程人员可以使用这个操作符来避免非法的转型。

这个示例在实现中会出现一个问题。payInstance()方法必须使用Employee引用emp并且向下转型以访问更新工资信息的适当子类方法。对于SalaryEmployee对象来说,适当的方法时getSalary()和setSalary();对于HourlyEmployee对象来说,适当的方法则是getHourlyPay()和setHourlyPay()。子类方法的选择取决于emp引用的实际子类对象。针对这种情况,Java提供了操作符instanceof。这个操作符将引用变量作为左侧的操作数,将类类型作为右侧的操作数,并且返回一个布尔值以表明引用变量是否引用给定类类型的对象。

语法:refVariable  instanceof ClassType   左侧是 引用变量  右侧是 类类型

示例:

 Time24 t = new Time24(9,30);

  if(t instanceof Time24)  // condition istrue

  {

  .....................

  }

payIncrease()方法的实现使用了instanceof操作符和一个if语句来判断Employee引用变量被传递给SalaryEmployee对象还是传递给了HourlyEmployee对象。这个选择表明了用于引用变量emp的转型以及更新工资信息所采用的方法。

 

payIncrease()方法:

 

 public static void payIncrease(Employee emp,double pct)

 {

if(empinstanceof SalaryEmployee)

((SalaryEmployee)emp).setSalary((1.0+pct)*((SalaryEmployee)emp).getSalary());

Else

((HourlyEmployee)emp).setHourlySalary((1.0+pct)*((HourlyEmployee)emp).getHourlySalary());

 }

 

instanceof操作符总结:其实就是 instance of 的意思,例如A instanceof B,就是A instance of  B,意思就是在问A是不是B的一个实例,如果是的话返回true;如果不是返回false。

 

 

变量不能被重写(覆盖),“重写”的概念只针对方法,如果在子类中“重写”了父类中的变量,那么在编译时会报错。


大家可能还是不是很理解 这篇文章有例子 点击打开链接    http://developer.51cto.com/art/200906/130414.htm


0 0