多态:可以理解为事物存在的多种体现形态
如:人:男人,女人
动物:猫,狗,鸟
猫这个动物应该是猫类型的:猫 cat = new 猫();
同时猫也是动物的一种:动物 y = new 猫(); 动物是猫和狗具体事物抽取出来的父类型,父类型指向了子类对象
1、多态的体现
父类的引用指向了自己的子类对象
父类的引用也可以接收自己的子类对象
2、多态的前提
必须是类与类之间有关系,要么继承,要么实现
还有一个前提:存在覆盖
3、多态的好处
多态的出现大大的提高了程序的扩展性
4、多态的弊端
虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员
5、多态的应用
6、多态使用的注意事项
看一个关于多态的例子:
abstract class Teacher { public abstract void teach(); public void sleep() { System.out.println("睡觉"); } } class MathTeacher extends Teacher { public void teach() { System.out.println("教数学"); } } class ChineseTeacher extends Teacher { public void teach() { System.out.println("教语文"); } public void sleep() { System.out.println("睡觉在沙发上"); } } //将代码进一步优化,定义一个工具类,这样就不需要实例化每一个老师对象,直接调用工具类,然后把各种类型的Teacher传进去既可 class TeachTest { public static void teach(Teacher t)//Teacher t类型是Teacher由于多态可以直接传MathTeacher等 { t.teach(); t.sleep(); } } class Test { public static void main(String[] args) { /* 实例化一个新的数学老师 Teacher t = new MathTeacher(); 类型提升,向上转型 t.sleep(); 如果想要调用猫的特有方法该怎么做? 强制将父类引用转成子类类型,向下转型 MathTeacher mt = (MathTeacher)t; mt.teach(); 就可以调用数学老师里面的教学方法 */ /* 如果要调用类的方法,先实例化一个类,然后分别调用 MathTeacher mt = new MathTeacher(); mt.teach(); mt.sleep(); ChineseTeacher ct = new ChineseTeacher(); ct.teach(); ct.sleep(); 发现这样比较麻烦,向上抽取,定义一个新的工具类TeachTest,将方法封装进去 */ TeachTest tt = new TeachTest(); tt.teach(new MathTeacher()); tt.teach(new ChineseTeacher()); } }
在多态中成员函数的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有,编译失败
在运行时期:参阅对象所属的类中是否有调用的方法
简单总结:成员函数在多态调用时,编译看左边,运行看右边
(面试)在多态中成员变量,静态成员函数的特点:
无论编译或运行,都参考左边(引用型变量所属的类)
如:
1 Fu f = new Zi(); 2 System.out.println(f.num);//打印的是父类里面的变量num 3 Zi z = new Zi(); 4 System.out.println(z.num);//打印的是子类里面的变量num 5 //静态的方法也是一样。
一个集合了接口,多态的例子
/* 类 主板,主板有运行方法run() 一段时间后想要上网 加入网卡类 想要听音乐 加入 声卡类 但是这样一个一个的加入使得代码的扩展性很差,每次都要重新修改很多代码 于是引入一个通用的接口PCI类 所有设备都有打开和关闭功能 让网卡和声卡分别取实现PCI接口,重写成自己的打开和关闭功能 给主板加上一个实现pcirun的方法,传递参数的值为PCI类型的 可以利用多态PCI p = new NetCard(); 所以在下面主函数中运行时 创建新的主板对象以后 mb.pcirun(new NetCard()); mb.pcirun(new SoundCard()); 就可以分别使用网卡和声卡了,如果以后还要再加入比如显卡 就只需要建立一个显卡类去实现PCI接口,然后直接用主板中的pcirun方法就可以了。 */ class MainBoard { public void run() { System.out.println("mainboard run"); } public void pcirun(PCI p) { p.open(); p.close(); } } interface PCI { public abstract void open(); public abstract void close(); } class NetCard implements PCI { public void open() { System.out.println("netcard open"); } public void close() { System.out.println("netcard close"); } } class SoundCard implements PCI { public void open() { System.out.println("SoundCard open"); } public void close() { System.out.println("SoundCard close"); } } class Test { public static void main(String[] args) { MainBoard mb = new MainBoard(); mb.run(); mb.pcirun(new NetCard()); mb.pcirun(new SoundCard()); } } /* 这样做的好处: 大大的降低了主板和各种独立设备直接的耦合性 中间用一个PCI接口来连接起来 程序日后非常方便扩展 */