1、什么是多态函数
“多态”是JAVA的一种重要特性,能够理解为事物存在的多种形态。优化
不过,这只是字面上来理解,等于废话。那么究竟何为多种形态呢,接下来,举一个现实生活中的例子。spa
好比,动物里有猫和狗。猫摆在面前,你可说它是猫,也能够说它是动物。code
说它是猫时,用JAVA语句表示即 猫 x=new 猫;对象
说它是动物时,用JAVA语句表示即 动物 x=new 猫;blog
这样,实体x即具有猫的类型,也具有动物类型。但必须一个前提,即“猫”必须是“动物”中的一种,若是“狗 x=new 猫”就不对了。继承
经过以上的例子,咱们能够看出,实体除了具有本类类型,还能够具有其它类型。这种是“多态”。编译
先看如下代码,这是使用非多态方式编写的class
代码以下:变量
package com.duotai; public class DuoTaiDemo { public static void main(String[] args) { myFun(new Cat()); myFun(new Dog()); myFun(new Pig()); } // 动物“吃”的功能提取出来封装成函数 public static void myFun(Cat c) { c.eat(); } public static void myFun(Dog d) { d.eat(); } public static void myFun(Pig p) { p.eat(); } } // 如下定义抽象类,定义了动物有“吃”的功能 abstract class Animal { abstract void eat(); // 动物吃什么不知道,定义成抽象。定义体系中的基本功能。只要继承了这个类,必有此功能。 } // 以定义具体类,复写动物的吃的功能,并有本身独特的功能 class Cat extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("猫吃鱼"); } public void catchMouse() { // 本身特有的方法 System.out.println("猫抓老鼠"); } } class Dog extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("狗吃骨头"); } public void kanJia() { // 本身特有的方法 System.out.println("看家"); } } class Pig extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("猪吃饲料"); } public void gongDi() { // 本身特有的方法 System.out.println("拱地"); } }
以上代码,定义了一个“动物”类,其有一个“吃”的功能,可是因为每种动物吃的方式都不同,因此定义成抽象类。之后让具体的动物去复写。
而后,定义了三个继承类,“猫”“狗”“猪”,复写了动物的“吃”的功能。
主函数调用时,要创建子类对的引用对象,再调用吃的方式。
这样编写时,会有一个弊端,那就是继承的子类若是增长时,则要修改主函数中的“吃”的代码。子类越多,这端代码就越长,扩展性比较弱。
如何优化呢?
子类“猫”,继承了“动物”类,是动物中的一种,那就能够用“动物”的引用来指向子类实例,即Aniaml c=new cat,c.eat(),运行结果是子类的,由于父类中有,子类中也有,就运行子类的eat(),由于子类复写了。这就是一个事物具有多种形态。
代码简化以下:
package com.duotai; public class DuoTaiDemo { public static void main(String[] args) { myFun(new Cat()); myFun(new Dog()); myFun(new Pig()); } // 动物“吃”的功能提取出来封装成函数 public static void myFun(Animal a){ //只要定义Animal便可。至关于Animal a=new Cat(); a.eat(); } } // 如下定义抽象类,定义了动物有“吃”的功能 abstract class Animal { abstract void eat(); // 动物吃什么不知道,定义成抽象。定义体系中的基本功能。只要继承了这个类,必有此功能。 } // 以定义具体类,复写动物的吃的功能,并有本身独特的功能 class Cat extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("猫吃鱼"); } public void catchMouse() { // 本身特有的方法 System.out.println("猫抓老鼠"); } } class Dog extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("狗吃骨头"); } public void kanJia() { // 本身特有的方法 System.out.println("看家"); } } class Pig extends Animal { public void eat() { // 复写Animal类的eat方法 System.out.println("猪吃饲料"); } public void gongDi() { // 本身特有的方法 System.out.println("拱地"); } }
2、多态的代码提现形式
父类的引用引向本身的子类对象。
父类的引用也能够接收本身的子类对象。如以上代码中:Animal a=new Cat()
3、多态的做用
提升了程序的扩展性
4、多态的前提
类与类有关系,必须是继承或是实现。如以上代码中,Cat、Dog、Pig类都继承了Animal类
一般还有一个前提,就是“复写”。如以上代码中,子父类中都有eat()方法,子类复写父类。
5、多态的弊端
提升了扩展性,可是只能是父类的引用访问父类中的成员
6、多类中数据的转型
在基本数据类型中,存在着数据类型提高现象,如double=2.3+1,会将1由int提高为double
在多类中,引用数据也存在数据提高。如以上Animal a=new Cat()中,Animal是父类型,Cat是子类型,将Cat提高为Animal,称为向上转型。
若是想要调用调用猫的特有方法(抓老鼠)时,能够强制将父类的引用转成子类对象。
咱们能转换的是父类引用指向本身的子类对象,该引用能够被提高,也可被强制向下转换
以下:
Animal c=new Cat();// Cat c1=(Cat)c; //向下转型 c1.catchMouse(); //输出猫的特有方法
在多态中,成员函数的特色:
一、编辑时期,参阅引用型变量所属的类中是否有调用方法。若是有编译经过,不然编译失败。
以下:Fu f = new Zi(),f所属的Fu中只有method1和method2,因此输出method3会编辑失败。
二、在运行时间,参阅对象所属的类中是否有调用方法。
以下:
Fu f = new Zi();
f.method1();
f.method2();
调用的是Zi类的方法,
简单总结,成员函数在多态调用时,编辑看左边,运行看右边
以下:
Fu类有method1和method2两个方法
Zi类中有method1和method3两个方法
Zi类中method1复写了Fu类中的method1,Zi类有三个方法
package com.duotai2; public class DuoTaiDemo { public static void main(String[] args) { Fu f = new Zi(); f.method1(); f.method2(); // f.method3(); //编译失败 } } class Fu { void method1() { // System.out.println("fu_method_1"); } void method2() { // System.out.println("fu_method_2"); } } class Zi extends Fu { void method1() { //复写 System.out.println("zi_method_1"); } void method3() { // System.out.println("zi_method_3"); } }
输出:
zi_method_1
fu_method_2
在多态中,成员变量的特色:
不管编辑和运行,只参考左边。以下
package com.duotai2; public class DuoTaiDemo { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); Zi z=new Zi(); System.out.println(z.num); } } class Fu { int num=5; } class Zi extends Fu { int num=8; }
输出:
5
8
在多态中,静态成员函数的特色:
不管编辑和运行,只参考左边。由于静态方法不须要建立对象,只要类名调用便可。
以下
public class DuoTaiDemo { public static void main(String[] args) { Fu f = new Zi(); f.method4(); Zi z=new Zi(); z.method4(); } } class Fu { static void method4() { // System.out.println("fu_method_4"); } } class Zi extends Fu { static void method4() { // System.out.println("zi_method_4"); } }
输出:
fu_method_4zi_method_4