面向对象三大特性:
面向对象三大特性分别是封装、继承和多态。今天我们来聊的是多态。如果对于前面继承的特性还不熟悉,需要先把继承相关知识学好再来学习多态;
一、多态的使用前提:
- 1.要有继承关系
- 2.要有方法的重写
为了便于理解,所以按照本人的习惯,先上代码:
子类继承父类代码:
package com.itheima.demo01多态介绍;
// 动物(父类)
public class Animal {
public void eat() {
System.out.println("动物在吃");
}
}
// 猫(子类)
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
// 狗(子类)
class Dog extends Animal {
public void eat() {
System.out.println("狗吃骨头");
}
}
测试类代码:
public class Demo01 {
public static void main(String[] args) {
// 之前的使用: 类名 对象名 = new 类名();
// 这个格式,右边不能切换
Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
// 多态:父类 变量名 = new 子类();
// 多态会走右边的子类方法
Animal a1 = new Dog();
a1.eat(); // 猫吃鱼/狗吃骨头
}
}
运行结果;
由以上代码,大家已经了解到了多态的表达方法;当然还有其他的多态表达形式,形式都大同小异。比如:
- 接口 变量名 = new 实现类();
- 抽象父类 变量名 = new 子类();
使用过程中应该注意到一点,他和我们曾经学过的基本数据类型转换其实很相似。在此过程中其实并没有产生新的对象,地址依旧是指向子类的(记住口诀:编译看左边,运行看右边),这点必须要注意。
二、多态的作用:
多态的好处:
调用方法的时候形成多态,方法的参数写父类,调用时可以传入任意的子类,提高代码扩展性。
我们单独这样讲其实大家比较难理解,还是直接上代码:
子类继承父类代码:
// 人类(父类)
public abstract class Person {
public abstract void eat();
}
// 学生(子类)
class Student extends Person {
@Override
public void eat() {
System.out.println("学生一边吃饭,一边学习");
}
}
// 老师(子类)
class Teacher extends Person {
@Override
public void eat() {
System.out.println("老师一边吃饭,一边备课");
}
}
// 工人(子类)
class Worker extends Person {
@Override
public void eat() {
System.out.println("工人一边吃饭,一边搬砖");
}
}
测试类代码:
public class Demo022 {
public static void main(String[] args) {
// 测试一:创建学生和老师
Student s = new Student();
Teacher t = new Teacher();
Worker w = new Worker();
kaiFan(s);
kaiFan(t);
kaiFan(w);
System.out.println("---------------------");
//测试二:
Person s1 = new Student();
Person t2 = new Teacher();
Person w3 = new Worker();
kaiFan(s1);
kaiFan(t2);
kaiFan(w3);
}
// 不用管具体的子类,给父类 父类 变量名 = new 子类(); 多态
// kaiFan(s); Person obj = s; Person obj = new Student();
// kaiFan(t); Person obj = t; Person obj = new Teacher();
public static void kaiFan(Person obj) {
obj.eat(); // 多态执行右边子类方法
}
// 模拟餐厅的开饭功能(这种方案相当于专用窗口,要写很多重载的方法)
// Student obj = s; Student obj = new Student();
/* public static void kaiFan(Student obj) {
}
// kaiFan(t); Teacher obj = t; Teacher obj = new Teacher();
public static void kaiFan(Teacher obj) {
}
*/
}
运行结果:
我们主要看测试类中的kaiFan(Person obj)方法,我们首先来复习一下实参和形参的概念,再来看,其实测试一和测试二结果都是一样的。由于kaiFan(Person obj)方法中的形参是Person类型,最终实参给他赋值的时候还是会形成多态。
下面我们来看看为什么要在测试类中单独搞一个方法,而不是利用对象直接调用方法。
原因:
单从以上代码,可能觉得实现上面的功能,用对象调取也一样只需要一行代码。但是,如实在子类中重写的很多个方法呢?这时,我们就需要多次利用对象调取,而正是这个时候才体现多态好处。