1、多态(polymorphism),多态的运行机制所谓“绑定(binding)”,就是建立methodcall(函数调用)和methodbody(函数本体)的关联。如果绑定动作发生于程序执行前(由编译器和连接器完成),称为“先期绑定”。对于面向过程的语言它们没有其他选择,一定是先期绑定。比如C编译器只有一种methodcall,就是先期绑定。(C+有先期联编和后期联编),当有多态的情况时,解决方法便是所谓的后期绑定(latebinding):绑定动作将在执行期才根据对象型别而进行。后期绑定也被称为执行期绑定(run-timebinding)或动态绑定(dynamicbinding)
3、把Feeder、Animal和Food都看成独立的子系统。Feeder类的定义如下:publicclassFeederpublicvoidfeed(Animalanimal,Foodfood)animal.eat(food);以下程序演示一个饲养员分别给一只狗喂肉骨头,给一只猫喂鱼。Feederfeeder=newFeeder();Animalanimal=newDog();Foodfood=newBone();feeder.feed(animal,food);animal=newCat();food=newFish();feeder.feed(animal
4、,food);,/给狗喂肉骨头,/给猫喂鱼,多态,Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换:Animalanimal=newDog();Dogdog=(Dog)animal;Creaturecreature=animal;如图2所示,如果把引用变量转换为子类类型,称为向下转型,如果把引用变量转换为父类类型,称为向上转型。在进行引用变量的类型转换时,会受到各种限制。而且在通过引用变量访问它所引用的实例的静态属性、静态方法、实例属性、实例方法,以及从父类中继承的方法和属性时,Java虚拟机会采用不同的绑定机制。,/向下转型,把Animal
5、类型转换为Dog类型,/向上转型,把Animal类型转换为Creature类型,多态,图2类型转换,多态,下面通过具体的例子来演示多态的各种特性。在下面的例程中,Base父类和Sub子类中都定义了实例变量var、实例方法method()、静态变量staticVar和静态方法staticMethod(),此外,在Sub类中还定义了实例变量subVar和subMethod()。Sub.javapackagepoly;classBaseStringvar=BaseVar;staticStringstaticVar=StaticBaseVar;voidmethod()Syst
6、em.out.println(Basemethod);staticvoidstaticMethod()System.out.println(StaticBasemethod);,/实例变量,/静态变量,/实例方法,/静态方法,多态,publicclassSubextendsBaseStringvar=SubVar;/实例变量staticStringstaticVar=StaticSubVar;/静态变量voidmethod()/覆盖父类的method()方法System.out.println(Submethod);staticvoidstaticM
9、r=“123”;/编译出错,提示在Base类中没有subVar属性who.subMethod();/编译出错,提示在Base类中没有subMethod()方法如果要访问Sub类的成员,必须通过强制类型的转换:BasewhonewSub();/who是Base类型(Sub)who).subVar=123;/编译成功,把Base引用类型强制转换为Sub引用类型(Sub)who).subMethod();/编译成功,把Base引用类型强制转换为Sub引用类型,多态,Java编译器允许具有直接或间接继承关系的类之间进行类型转换.对于向上转型,不必使用强制类型转换,因为子类的对象肯定也
10、可看作父类的对象。例如一个Dog对象是一个Animal对象,也是一个Creature对象,也是一个Object对象:Dogdog=newDog();Creaturecreature=dog;/编译成功,把Dog引用类型直接转换为Creature引用类型Objectobject=dog;/编译成功,把Dog引用类型直接转换为Object引用类型对于向下转型,必须进行强制类型转换:Creaturecreature=newCat();Animalanimal=(Animal)creature;/编译成功,把Creature引用类型强制转换为Animal引用类型Catca
11、t=(Cat)creature;/编译成功,把Creature引用类型强制转换为Cat引用类型Dogdog=(Dog)creature;/编译成功,把Creature引用类型强制转换为Dog引用类型,多态,假如两种类型之间没有继承关系,即不在继承树的同一个继承分支上,那么Java编译器不允许进行类型转换,例如:Dogdog=newDog();Catcat=(Cat)dog;/编译出错,不允许把Dog引用类型转换为Cat引用类型(2)对于一个引用类型变量,运行时Java虚拟机按照它实际引用的对象来处理。例如以下代码虽然编译可以通过,但运行时会抛出ClassCastExcepti
12、on运行时异常:Basewho=newBase();/who引用Base类的实例Subs=(Sub)who;/运行时抛出ClassCastException在运行时,子类的对象可以转换为父类类型,而父类的对象实际上无法转换为子类类型。因为通俗的讲,父类拥有的成员子类肯定也有,而子类拥有的成员父类不一定有。,多态,假定Java虚拟机能够把子类对象转换为父类类型,那么以下代码中的sub.subMethod()方法无法执行:Basewho=newBase();/who引用Base类的实例Subsub=(Sub)who;/假定运行时未出错sub.subMethod();/s
13、ub引用变量实际上引用Base实例,而Base实例没有subMethod()方法由此可见,在运行时,Java虚拟机无法把子类对象转变为父类类型。以下代码尽管能够编译成功,但在运行时,creature变量引用的Cat对象无法转变为Dog类型,因此会抛出ClassCastException:Creaturecreature=newCat();Animalanimal=(Animal)creature;/运行正常,Cat对象可转换为Animal类型Catcat=(Cat)creature;/运行正常,Cat对象可以被Cat类型的引用变量引用Dogdog=(Dog)creature
16、VarSubmethodStaticBasemethod,多态,再看一个例子:publicabstractclassAabstractvoidmethod();voidtest()method();/到底调用哪个类的mehtod()方法?publicclassBextendsAvoidmethod()/覆盖父类的method()方法System.out.println(Sub);publicstaticvoidmain(Stringargs)newB().test();,多态,运行类B的main()方法将打印Sub。方法test()在父类A中定义
17、,它调用了方法method()。虽然方法method()在类A中被定义为是抽象的,它仍然可以被调用,因为在运行时环境中,Java虚拟机会执行类B的实例的method()方法。一个实例所属的类肯定实现了父类中所有的抽象方法(否则这个类不能被实例化)。再看一个例子:publicclassAvoidmethod()System.out.println(Base);voidtest()method();publicclassBextendsAvoidmethod()System.out.println(Sub);publicstaticvoidmain(Stringargs)newA().test();/调用类A的method()方法newB().test();/调