多态(polymorphism)就是指一个名字,多种形式。Java中多态是指方法的多态,包括方法重载导致的静态多态和方法重写导致的动态多态。
(1)静态多态:又称为编译时多态。在编译阶段,具体调用哪个被重载的方法,编译器会根据参数的不同来静态确定相应的方法。这种多态在代码编译阶段就确定了。
(2)动态多态:又称为运行时多态。这种多态存在的前提是:一要有继承关系;二要子类重写父类相关方法;三是父类引用指向子类对象。
由于继承是“is-a”的关系,因此使用父类对象的地方都可以用子类对象代替。当父类对象引用变量(属于声明类型或编译类型)指向子类对象(属于实际类型或运行时类型)时,程序会在运行时选择正确的方法。
【例4-6】
设计用例演示动态多态效果。
步骤1:在cn.linaw.chapter4.demo01包中,复制His Triangle4.java,粘贴到同一个包下,并重命名为His Triangle5.java。
步骤2:在His Triangle5类中增加新功能isRight Angled Triangle方法,用于判断该三角形是否是直角三角形,如图4-20所示。
图4-20 在HisTriangle5类中增加新功能
步骤3:通过测试类His Triangle5Test来演示多态性,如图4-21所示。(www.xing528.com)
图4-21 运行时多态性示例
程序说明如下:
(1)程序第5行声明了一个HisGraph类的引用变量g,而实际指向的是子类His Triangle5类创建的对象。因此,变量g声明类型是HisGraph,而被变量引用的对象的实际类型是His Triangle5,赋值时引用类型做了自动向上转型。
(2)程序第6行执行g.isRight Angled Triangle()时编译报错,因为指向子类对象的父类引用只能访问父类中拥有的成员,HisGraph类中并没有定义isRight Angled Triangle()方法。因此,编译时先看变量的声明类型,声明类型决定了编译时匹配哪个方法,而运行时看对象的实际类型,进行动态调用,体现多态。简言之,编译看左边,运行看右边。
(3)程序第8行执行g.get Area()时,会先到His Triangle5类中根据方法名(参数列表)查找,如果没匹配成功,再到His Triangle5类的父类中继续查找,直到找到时停止。因此,调用的是系统第一次找到的方法,这就是运行时动态调用的原理。具体到本例,搜索get Area()方法,在子类His Triangle5中第一次匹配成功,执行该方法。可见,多态机制下,如果子类重写了父类某些方法,父类引用在调用这些方法时,实际使用的是子类重写后的方法。
(4)如果要执行子类对象的特有方法,该怎么办?那就要用到对象的向下转型。
向上转型的弊端是父类引用变量只能调用它编译类型(声明类型)的方法,而不能调用它运行时类型(实际类型)的特有方法。如果需要运行,就需要进行类型的向下转型,将引用变量转换成对象运行时的子类类型,这是显式的、强制的。如程序第10行就属于类型的强制向下转型,将父类引用变量g向下强制转换为真实的子类类型His Triangle5变量t,然后通过引用变量t即可调用His Triangle5类的所有方法,如程序第12行的t.isRight Angled Triangle()。
类型的向上转型是自动的,但向下转型要慎重,例如三角形是图形,但图形不一定是三角形。为了避免强制向下转型出现的异常,Java提供了instanceof运算符来判断。
instanceof运算符是二元运算符,左边是对象引用变量,右边是类名。当左边引用的对象是右边的类或其子类所创建的对象时,返回true,否则返回false。程序第9行的布尔表达式“g instanceof His Triangle5”,当引用变量g指向的对象是His Triangle5类或其子类对象时,返回true。先利用instanceof运算符判断,后执行类型的强制向下转型是一种推荐的做法。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。