1.多态的实现
2.多态的优点与缺点
3.向上转型和向下转型
4.instanceof 关键字
5.项目代码体现多态
6.多态的成员调用
1.多态的实现
多态的实现就是:通过一个抽象的东西(可以是父类,可以是接口),可以随时变成任意一个符合要求的具体的东西。
例如图形:可以通过具体情形给他定义为 圆形,矩形,菱形等。
通过父类实现多态:
父类能够选择性地在多个子类中选择一个子类,调用该子类中与 父类中的方法 同名的方法。
选择一个子类后,然后用父类的引用指向该子类的对象即可。
注意:父子类方法同名的情况下,父类的方法会别子类同名的方法覆盖掉。
步骤:
1.定义父类。定义父类的方法
2.子类继承父类。
3.子类中具体定义与 父类具有的方法 同名的方法。
4.主函数中用父类的引用指向子类的对象。
如:
class Parent { void work() { System.out.println("go to work"); } void cook() { System.out.println("Parent cook"); } } class Child extends Parent { void play() { System.out.println("play"); } void cook() //与父类同名的方法 { System.out.println("Child cook"); } } public class Main { public static void main(String[] args) { Parent p = new Child(); //实现多态。父子类方法同名的情况下,父类的同名方法会别覆盖掉 p.cook(); } } //打印结果:Child cook
2.多态的优点与缺点
1.优点:多态用于抽象类--提高了代码的扩展性
例如,一个游戏中,有几种动物,有狗,有马。动物类是抽象类,狗类和马类是具体子类,基于多态,用动物类的引用指向子类的对象,就可以用动物类调用子类的具体方法(就相当于抽象的动物类变成了具体动物)。当游戏更新,要更新一个新的动物---猫类。这个时候,也不用怕,定义好猫类(实现好动物类固有的抽象方法),动物类就可以通过多态,直接变成猫,这样子就提高了扩展性。
abstract class Animal { public abstract void eat(); } class Dog extends Animal { public void eat() /*方法名必须与抽象父类中的抽象方法同名*/ { System.out.println("eat bone"); } } class Cat extends Animal { public void eat() /*方法名必须与抽象父类中的抽象方法同名*/ { System.out.println("eat fish"); } } public class Main { public static void main(String[] args) { Animal a = new Dog(); //抽象动物类可以指向狗类也可以指向猫类 Animal b = new Cat(); a.eat(); b.eat(); } } //打印结果:eat bone // eat fish
2.缺点:多态之后的父类不能调用子类特有的方法。
多态只能调用子类中与父类的抽象方法同名的方法。而不同调用子类中特有的方法。
3.向上转型和向下转型
向上转型就是子类对象变为父类。
向下转型就是父类对象变为子类。
1.向上转型
Animal a = new Dog();//这就是向上转型,把狗提升为Animal ,即此时Animal就相当于Dog 好处:提升了程序扩展性
弊端:限制使用Dog类的功能,Animal只能使用Animal类中定义了的功能,而不能使用Dog类中特有的功能。
2.向下转型
Animal a = new Dog(); Dog d = (Dog)a;//向下转型,把Animal变回Dog 好处:可以使用Dog类中特有的功能。
弊端:类型容易错,当Animal a = new Cat()时,那么Dog d = (Dog)a 就错了,因为a多态Dog类。这时候就要进行类型判断。类型判断用instanceof关键字。
注意:无论是向上还是向下转型,本质都是自始至终只有子类对象在做着变化。
4.instanceof 关键字
用于判断某对象是否属于某类。是就返回ture,否则返回false
abstract class Animal { public abstract void eat(); } class Dog extends Animal { public void eat() /*方法名必须与抽象父类中的抽象方法同名*/ { System.out.println("eat bone"); } } public class Main { public static void main(String[] args) { Animal a = new Dog(); if(a instanceof Dog) { System.out.println("a is Dog"); } } } //打印结果:a is Dog
5.项目代码体现多态
需求:体现计算机支持多种USB设备
思路:若每增加一个设备就在笔记本类中添加相应的函数,那么代码的扩展性能就差,程序耦合性太强。 因为你向增加笔记本功能就要修改笔记本的类代码。那有没有方法可以不修改笔记本类的代码来实现笔记本的功能扩展呢?使用多态就可以。
只要笔记本类中有使用USB接口代码,就能通过多态,使implement实现了USB接口的类传进笔记本类中。
/*用于提供功能的接口*/ interface USB { /*定义USB设备的功能:*/ public abstract void open(); public abstract void close(); } /*USB鼠标类*/ class UsbMouse implements USB { public void open() { System.out.println("Mouse open"); } public void close() { System.out.println("Mouse close"); } } /*USB键盘类*/ class UsbKeyBorad implements USB { public void open() { System.out.println("Keyborad open"); } public void close() { System.out.println("Keyborad close"); } } /*笔记本的主体类*/ class NoteBook { public void UseUSB(USB usb) //传递USB接口的引用.接口虽然不能实例化,但能够传递他的引用。 { if(usb!=null) { usb.open(); usb.close(); } } } public class Main { public static void main(String[] args) { NoteBook computer = new NoteBook(); computer.UseUSB(new UsbMouse()); //相当于 USB usb = new UsbMouse(); computer.UseUSB(new UsbKeyBorad()); //相当于 USB usb = new UsbKeyborad(); } } //打印结果: /*Mouse open Mouse close Keyborad open Keyborad close */
其实 main()函数就相当于用户。main函数中写 public void UseUSB(new USB鼠标())就相当于我们用户把鼠标的usb口插进了电脑的usb接口中。
6.多态的成员调用
1.对于变量
对于变量来说,多态是 父类引用指向子类对象。即: Parent p = new Child();如果Parent类和Child类中都有同名变量num,那么 p.num 是调用父类的num还是子类的num呢?答案是父类的num。因为 Parent p = new Child();已经把子类对象向上转型为父类对象了,所以调用的就是父类的num,如果父类中没num变量,而子类有,执行 p.num 就会发生错误,因为父类中并没num。
2.对于函数
出现同名函数(例如叫fun)时,Parent p = new Child();p.fun 是调用的是子类的fun函数,而不是父类的。但若父类中没有 fun 函数,子类有fun,那程序会报错,因为通过 Parent p = new Child();子类对象已经向上转为父类了。
3.对于静态函数
静态函数只能类有关系,跟对象没关系。静态函数直接绑定在类上,所以即使父类和子类都有同名的静态函数(StaticFun),执行多态时 Parent p = new Child(); p.StaticFun() 是调用父类的静态函数
总结:对于函数而言,非静态的函数是跟对象绑定的,而静态的函数是跟类绑定的。
