1.多态基本介绍
首先我们要搞清楚几个基本问题,什么是多态?多态是用来干什么的?多态现实意义是什么?
(1)什么是多态?
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
(2)多态是用来干什么的?
封装、继承、多态是面向对象编程的三大特性。我们知道,封装可以隐藏实现细节,使得代码可以模块化;继承可以扩展已经编写好的代码类。他们的主要目的都是为了——代码重用。而多态除了解决代码复用性问题之外,还可以解决项目中紧耦合的问题(模块之间关系太紧密,存在相互调用。),提高程序的可扩展性。
(3)多态现实意义是什么?
现实里面,事物经常会出现多种形态。比如说,张三是学生,同时张三也是一个人,即出现两种形态。
2.多态定义
-
多态是继封装、继承之后,面向对象的第三大特性。
-
实现多态的前提条件是,必须有父类子类关系。
-
多态的定义和使用格式:
定义格式:父类类型 变量名 = new 子类类型();
3.多态成员特点
等式左边是编译类型,等式右边是运行类型。
定义两个类AA和BB,用于展示多态成员特点。其中BB继承AA。
class AA{
public int num = 10;
public void say(){
System.out.println("这是AA类的say方法");
}
}
class BB extends AA{
public int num = 20;
public void say(){
System.out.println("这是BB类的say方法");
}
}
(1)多态成员变量
属性没有重写之说!属性的值看编译类型的属性值。
public class polymorphic {
public static void main(String[] args) {
AA aa = new BB();
System.out.println(aa.num);//输出 10
}
}
(2)多态成员方法
调用方法时,按照从子类(运行类型)开始查找方法,子类没有则逐级往上,然后调用。
注意:只能运行编译类型拥有的方法,如果运行类型没有对应的方法,则执行编译类型的方法。
public class polymorphic {
public static void main(String[] args) {
AA aa = new BB();
//因为运行时,aa的运行类型是BB,所以执行BB的say方法
aa.say(); //输出 这是BB类的say方法
}
}
4.instance of 关键字
作用:返回类型为布尔类型,用于判断某个对象的运行类型是否为XX类型或者XX类型的子类型
public class polymorphic {
public static void main(String[] args) {
AA aa = new BB();
System.out.println((aa instanceof BB));//输出true,说明aa的运行类型是BB
}
}
5.多态的转型
(1)向上转型
多态本身就是一个向上转型的过程。
使用格式:父类类型 变量名 = new 子类类型();
AA aa = new BB();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作(需要遵守访问权限)。
(2)向下转型
使用格式:子类类型 引用名 = (子类类型) 父类引用;
AA aa = new BB();
BB bb = (BB) aa;//向下转型
注意:要求父类的引用必须指向的是当前目标类型的对象。 下面用一个例子来说明。
//新建了一个类CC来证明
class CC extends AA{}
AA aa = new BB();//向上转型
BB bb = (BB) aa;//向下转型
CC cc = (CC) aa;//此处不通过,报错。
此处,AA是BB和CC的父类,但是BB和CC之间没有直接联系,cc不能指向对象BB,就会报错。
适用场景:当需要使用子类特有功能的时候。
6.动态绑定机制
新建两个类来说明Java多态中的动态绑定机制。
class A{//父类
public int i = 10;//动态绑定机制
public int sum(){
return getI() + 10;//20+10
}
public int sum1(){
return i + 10;//10 + 10
}
public int getI(){
return i;
}
}
class B extends A{//子类
public int i = 20;
// public int sum(){
// return i + 20;
// }
public int getI(){
return i;
}
// public int sum1(){
// return i + 10;
// }
}
实例运行
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//? 30
System.out.println(a.sum1());//? 20
}
}
-
当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
如上面的例子, 子类中没有 sum() 方法,因此调用父类的。父类的 sum() 方法中调用了 getI() 方法,因此从子类中查找 getI() 方法(因为a的运行类型是B)。由于子类中定义的 i 值为20,所以 sum() 方法得到的值为 20 + 10 = 30 。
-
当调用对象类型时,没有动态绑定机制,哪里声明,哪里使用(属性没有动态绑定机制)
同理,在调用 sum1() 方法时,由于子类没有此方法,因此调用父类的方法。由于属性没有动态绑定机制,父类中声明的 i 值为10,因此 sum1() 方法得到的结果是10 + 10 = 20
7.多态的应用
具体多态的应用举例看多态的应用实际举例