????? 从前面的继承(Inheritance)到比较this和super,所用的例子都夹杂着多态(Polymorphism)的味道。所以,这篇就是阐述个人总结的多态(Polymorphism)
?
????? 多态,并没有关键字,可以视之为Java的三大特性之一,也可以视为继承“is a”的另一阐述“substitution principle(代理准则)”的体现。在Java中,对象变量(引用变量)是多态的,如:
Employee e; // e为对象变量 e = new Employee(...); e = new Manager(....);
????? 变量是多态的,但是还有有些规律可循的,那就是父类的对象变量既可以指向父类实例,也可以指向子类实例,但是子类的对象变量只能指向子类实例。
????? 相关代码:
package com.PolymorphismTest;
/**************************************************
* simply introduce something about basic polymorphism,群:152380972
* @author: 瘋叻ハ.兩
* @revision: 1.0
* @create-time: 2011-9-6 下午06:30:33
***************************************************/
public class PolymorphismTest1 {
public static void main(String[] args){
// create arrays Employee
Employee1[] e1 = new Employee1[2];
// create a manager object
Manager1 boss = new Manager1("John", 8000, 500);
// it's correct for superclass object to refer subclass object or its'object
e1[0] = boss;
e1[1] = new Employee1("Kevin", 4500);
// it's wrong for subclass object refers to superclass object
// Manager1 m = e1[1];
// e1[i] was considered to be only an Employee1 object by the compiler(编译器)
e1[0].getSalary();
// e1[0].setBonus(); // won't work
for(Employee1 e : e1){
System.out.println(e.getName() + "的工资是:" + e.getSalary());
}
}
}
class Employee1{
private String name;
private int salary;
// default constructor
public Employee1(){
}
// constructor with fields
public Employee1(String n, int s){
name = n;
salary = s;
}
public String getName() {
return name;
}
public int getSalary() {
return salary;
}
}
class Manager1 extends Employee1{
private int bonus;
public Manager1(String n, int s, int b){
super(n, s);
this.bonus = b;
}
// override method getSalary
@Override
public int getSalary(){
int baseSalary = super.getSalary();
return baseSalary + bonus;
}
}
?
??????运行结果:???
?????????????????? John的工资是:8500
?????????????????? Kevin的工资是:4500
?
????????分 析? :且看下文
?
????? 从上面程序的结果,我们会有这样的疑惑,编译时都是是Employee1类型的变量,为什么结果不是“8000,4500”而是“8500,4500”呢? 答案就是方法的动态绑定(Dynamic Binding),多态的表现形式。简单的说,Java中的对象变量有2中:编译类型和运行类型。编译类型由声明该变量使用的类型决定,运行类型由实际赋给该变量的对象决定。当执行至e1[0].getSalary( )时,因为e1[0]指向boss,而boss是Manager1类型,所以此时的getSalary( )方法是Manager1中的。下面代码希望助你理解编译类型和运行类型。
??????相关代码:
package com.PolymorphismTest; /************************************************** * differentiate from compiled type and running type,群:152380972 * @author: 瘋叻ハ.兩 * @revision: 1.0 * @create-time: 2011-9-6 下午08:04:15 ***************************************************/ public class TypeTest { public static void main(String[] args) { // declare the Animal object Animal a = new Lion(); // print the actual class of a System.out.println(a.getClass()); // use photo 1 to identify what compiled type the variable is a.run(); } } class Animal{ // what does it work? // in fact, a's compiled type is Animal. when program is compiled, "a.run()" use this method not Lion's public void run(){ System.out.println("Animal can run!"); } } class Lion extends Animal{ @Override public void run(){ System.out.println("Lion is running..."); } }
????? 运行结果:?
?????????????????? class com.PolymorphismTest.Lion
???????????????????Lion is running...
?
???????? 分? 析 :看代码注释
?
?????
????? 关于Animal处的代码注释如果意思不懂,且看多态方法调用的4步曲,知道的可忽视而过。(选自Java核心技术卷1:基础知识)以【 x.f(param) x是C类,x的子类是D类 】为例:
????? 1、根据对象编译类型确定方法名。 编译器首先找的是对象的声明类型和方法名称。所以可以通过x的类型排除其他类型的f方法。但是不能排除f的重载方法,即不同参数类型的同一方法。在本例中,编译器以C类型排除非C类型的f方法,而不是D
?
??????2、根据形参类型名确定具体方法名。 根据传入的形参类型查找相应的方法就能确定具体是哪个方法了,这个过程也称为“overloading resolution”。
?
????? 3、根据修饰词确定绑定状态。? 如果方法被private、static、final修饰,那么这些方法就是static binding,否则是dynamic binding。
?
????? 4、根据绑定状态执行方法体。?当方法是dynamc binding,虚拟机会找到方法执行者的指向类型,即运行类型。如果运行中有同名方法,则执行该方法的方法体,否则执行父类中的方法体。在本例中,如果D类中有f方法,便执行D类的方法,否则执行C类的f方法。当方法是static binding,在多态中是没有意义的,所以就不介绍了
?
?
????? 多态,其实就是对象变量的多态,它的表现形式就是控制方法。可以发现,它的成立条件就是有继承关系。所以说,多态也是继承“is a”的另一阐述“substitution principle(代理准则)”的体现!
?
????? 事后补充,请原谅我的疏忽
????? 对象变量的多态,并不影响到属性的访问,即通过引用变量访问其包含的实例属性时,系统总是访问其编译时类所定义的属性,而不是它运行时类所定义的属性。
????? 相关代码:
/************************************************** * whether polymorphism influence to access attribute! 群:152380972 * @author: 瘋叻ハ.兩 * @revision: 1.0 * @create-time: 2011-9-7 上午12:07:06 ***************************************************/ public class TypeTest1 { public static void main(String[] args) { Animal1 a1 = new Lion1(); System.out.println("名称是:" + a1.name); } } class Animal1{ public String name = "动物"; } class Lion1 extends Animal1{ public String name = "Lion"; }
?
??????运行结果:
???????????????????? 名称是:动物
?
??????? 分??析? :对象变量的多态不影响属性的访问
?
?