黑马软件工程师_<<面向对象(多态)-03>>
---------------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------
1.多态
1. 概述
多态:某一类事物的多种存在形态
因为有的继承,所以有了父类和子类关系,那么就提现出来了多态的特性。
当一类事物之间肯定有存在某种关系,例如儿子和父亲,学生和人,工人和人,那么他们也有共性,那么当我们划分的越细,那么子类就越多,那么我们调用相同特性的时候,就会比较麻烦,那么我们就使用父类来接受子类的对象,这样就可以调用相同的特性方法。
例如:
动物:狗,猪,兔子…等,他们都有吃的行为。
interface Animal { void eat(); } public class Dog implements Animal { /*重写父类的方法*/ public void eat() { System.out.println("狗吃骨头"); } } public class Pink implements Animal { /* 重写父类的方法 */ public void eat() { System.out.println("猪吃猪饲料"); } } public class DuoTaiDemo { public static void main(String[] agrs) { animalEat(new Dog()); animalEat(new Pink()); } /** * 用父类来接受子类,那么就可以调用子类和父类相同的方法 */ public static void animalEat(Animal animal) { animal.eat(); } } 结果: 狗吃骨头 猪吃猪饲料
从结果可以看出,父类可以接受子类对象,相当于 Animal animal=new Dog();
结论:父类的引用指向了自己的子类对象。
父类的引用也可以接受自己的子类对象。
2. 多态的特点
要想使用多态,那么前提是:类与类之间必须有关系,存在覆盖。
多态的好处:提高了程序的扩展性,也可以减少代码。
多态的弊端:只能使用父类的引用访问子类和父类共有的方法。
3. 多态的应用
使用:可以使用父类对象作为参数接受子类对象。
向上转型:子类类型转换成父类类型。
向下转型:强制把父类的引用转换成子类类型。
Instanceof:判断是否是此类型 子类是有限的,或者是对某一特殊类型进行转换。
也可以重写基类的方法,然后把共有的方法封装到一个新的类中,这样使用就更方便了。
interface Animal { void eat(); } public class Dog implements Animal { /* 重写父类的方法 */ public void eat() { System.out.println("狗吃骨头"); } /* 自独有的方法 */ public void seeDoor() { System.out.println("看门"); } } public class Pink implements Animal { /* 重写父类的方法 */ public void eat() { System.out.println("猪吃猪饲料"); } /* 自独有的方法 */ public void DongDi() { System.out.println("猪,gongdi"); } } public class DuoTaiDemo { public static void main(String[] agrs) { animalEat(new Dog()); animalEat(new Pink()); } /** * 用父类来接受子类,那么就可以调用子类和父类相同的方法 */ public static void animalEat(Animal animal) { animal.eat(); /*instanceof 是判断是否是此类对象,十寸与此类存在某种关系 * 一般情况下,只有在子类比较少的情况下,才使用此比较的方式, * 父类不能调用子类自己独有的方法,必须强制转换成子类对象*/ if(animal instanceof Dog){ Dog dog=(Dog)animal; dog.seeDoor(); }else if(animal instanceof Pink){ Pink p=(Pink)animal; p.DongDi(); } } } 结果; 狗吃骨头 看门 猪吃猪饲料 猪,gongdi
4. 覆盖问题
多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法,。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
当父类和子类相同的成员变量,或者有相同的静态方法,那么父类接受子类对象的时候,那么调用相同的成员变量或者是相同的静态方法,那么就执行父类的, 因为,当父类和子类一加载的时候,那么其都在内存中生成,所以当然会调用弗雷德。
如果不是静态的方法那么会调用子类重写的方法。
public class Fu { public int num=5; /*静态成员*/ public static void show(){ System.out.println("父类的静态的show()方法"); } public void print(){ System.out.println("父类的非静态的print()方法"); } } public class Zi extends Fu { public int num=10; public static void show(){ System.out.println("子类的静态的show()方法"); } public void print(){ System.out.println("子类的非静态的print()方法"); } public static void main(String[] agrs) { Fu fz = new Zi(); fz.show();//父类的,因为是静态的方法 System.out.println(fz.num);//父类的,因为是常量 fz.print();//子类的,因为不是静态的 } } 结果: 父类的静态的show()方法 5 子类的非静态的print()方法
2. 示例
模拟电脑的主板和PCI功能。主板中封装了PCI,其他的网卡,声卡都实现PCI接口,不管是以后扩展什么,那么继承PCI就可以在主板上上运行。
/*PCI接口*/ interface PCI { void open(); void close(); } /*主板*/ class MainCard { public void run() { System.out.println("main cardrun"); } public void userPCI(PCI pci) { if (pci != null) {// 加入PCI上不为空, pci.open(); pci.close(); } } } /* 网卡 */ class NetCard implements PCI { @Override public void close() { System.out.println("NetCard open"); } @Override public void open() { System.out.println("NetCardclose"); } } /* 声卡 */ class SoundCard implements PCI { @Override public void close() { System.out.println("SoundCardopen"); } @Override public void open() { System.out.println("SoundCardclose"); } } public class TextDemo { public static void main(String[] args) { MainCard card = new MainCard(); card.run(); card.userPCI(new NetCard()); card.userPCI(new SoundCard()); } } 结果: main card run NetCard close NetCard open SoundCard close SoundCard open