面向对象特征之三:多态性
一、概念
1、多态性
- 多态性是面向对象中最重要的概念,在java中有两种体现
- 方法的重载(overload)和重写(overwrite)
- 重载:本类中的同名方法
- 如何实现多态性:
- 体现相同的名称方法实现不同的逻辑
- 如何实现多态性:
- 重写:子类对父类方法的覆盖
- 如何实现多态性:
- 子类可以使用和 父类相同的同名方法,覆盖掉父类的逻辑
- 父类的方法,想修改逻辑,但是有别的代码在调用父类的方法,可以考虑用子类继承父类,重写父类的方法
- 如何实现多态性:
- 重载:本类中的同名方法
- 对象的多态性
可以直接应用在抽象类和接口上
2、java引用变量有两个类型:
-
编译时类型和运行时类型。
-
编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋值给该变量的对象决定。
- 若编译时类型和运行时类型不一致,就出现多态(Polymorphism)——这是对象的多态
二、对象的多态
在Java中,子类的对象可以替代父类的对象使用
- 一个变量只能有一种确定的数据类型
- 一个引用类型变量可能指向(引用)多种不同类型的对象
//正常情况下
Person p = new Person();
Student s = new Student();
//父类的引用对象可以指向子类的示例
//向上转型
Person e = new Student();//Person类型的变量e,指向Student类型的对象
Person p = new Person();
p = new Student();
//当前这个引用对象p引用的是student实例对象
- 子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型
- 子类的对象可以给父类的类型的变量引用
- 一个引用变量类型如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
Student m = new Student();
m.school = "pku";//合法,Student类有school成员变量
Person e = new Student();
e.school = "pku";//非法,Person类没有school成员变量
- 属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。
三、虚拟方法调用
1、正常的方法调用
Person p = new Person();
p.getInfo();//调用Person类的getInfo方法
Student s = new Student();
s.getInfo();//调用Student类的getInfo方法
2、虚拟方法调用(多态情况下)
Person e = new Student();
e.getInfo();//调用Student类的getInfo方法
3、编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定
四、多态小结
1、前提
- 需要存在继承或者实现关系
- 要有覆盖操作
2、成员方法
成员方法的多态性,也就是动态绑定,必须得存在于方法的重写之上。
- 编译时:
- 要查看引用变量所属的类中是否有所调用的方法
- 运行时:
- 调用实际对象所属的类中的重写方法
3、成员变量
不具备多态性,只看引用变量所属的类
4、子类继承父类
- 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中。
- 如果子类没有重写父类的方法,那么子类就是直接使用父类的方法
- 如果重写了,子类就使用自己重写之后的
- 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量。
- 如子类和父类都定义了
int age
五、多态性应用举例
方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test{
public void method(Person e){
//...
e.getinfo();
}
public static void main(String[] args){
Test = new Test();
Student m = new Student();
t.method(m);//子类的对象m传送给父类类型的参数e
}
}