第13讲
1 多态简述
同一个对象,在不同时刻表现出来的不同形态就叫多态
- 例如:
- 猫是猫:猫 cat = new 猫()
- 猫是动物:动物 animal = new 猫()
多态的形式:
- 具体类多态
- 抽象类多态
- 接口多态
2 多态的使用前提
-
有 继承 / 实现 关系
-
有方法重写
-
有父(类 / 接口)引用指向(子 / 实现)类对象👇
//父类引用 指向 子类对象 父类 对象名 = new 子类名(); //父接口引用 指向 实现类对象 接口名 对象名 = new 实现类名();
3 多态中成员访问特点
public class Animal() {
public int height = 10;
public void eat() {
Sout: "动物吃东西";
}
}
class Cat extends Animal() {
public int height = 20;
public int weight = 40;
@Override
public void eat() {
Sout: "猫吃鱼";
}
public void play() {
Sout: "猫玩老鼠";
}
}
3.1 成员变量
编译看左边,运行看左边 (因为成员变量没有重写)
- 编译看左边:
javac
在编译代码的时候,会看左边(父类)有没有这个成员变量 - 运行看左边:
java
在运行代码的时候,会拿左边(父类)的成员变量的值作为最终值
public class Demo() {
public static void main(String[] args) {
Animal ani = new Cat();
Sout: ani.height;// 输出:10 (来自父类)
Sout: ani.weight;// 报错,因为Animal类里没有成员变量weight
}
}
3.2 成员方法
编译看左边,运行看右边 (因为成员方法有重写)
- 编译看左边:
javac
在编译代码的时候,会看左边(父类)有没有这个成员方法 - 运行看右边:
java
在运行代码的时候,会拿右边(子类)的成员方法作为最终值
public class Demo() {
public static void main(String[] args) {
Animal ani = new Cat();
ani.age();// 输出:猫吃鱼 (来自子类)
ani.play();//报错,因为Animal类没有成员方法play()
}
}
4 多态的利与弊
好处
-
定义方法时,
使用父类型作为参数,可以接收所有的子类对象
。以后再使用的时候,只需要使用具体的子类型参与操作即可。提高了程序的扩展性 -
在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
如 A extends C, B extends C。C类中有一个工作:打扫卫生。
起初A类对象在打扫卫生:
C c = new A();
c.work();
现在想让B类对象去打扫卫生,只需要改变子类对象
C c = new B();
,后续所有的代码都不需要更改。
弊端
- 不能使用子类的特有功能(解决方法见下:多态的转型)
public class Demo() {
public static void main(String[] args) {
Animal ani = new Cat();
ani.age();// 输出:猫吃鱼 (来自子类)
ani.play();//报错,因为Animal类没有成员方法play()
}
}
class Animal() {
public int height = 10;
public void eat() {
Sout: "动物吃东西";
}
}
class Cat extends Animal() {
public int height = 20;
public int weight = 40;
@Override
public void eat() {
Sout: "猫吃鱼";
}
public void play() {
Sout: "猫玩老鼠";
}
}
5 多态的转型
5.1 向上转型(自动类型转换)
从子到父
- 父类引用指向子类对象
//向上转型
Animal ani = new Cat();
5.2 向下转型(强制类型转换)
从父到子
- 父类引用转为子类对象
作用: 可以转为真正的子类类型,从而调用子类独有的功能
转换类型与真实对象类型不一致的时候会报错,所以:
转型需谨慎,要加以判断:
语法:a instanceof B
//变量a是不是B类型,如果是,返回true
public class Demo() {
public static void main(String[] args) {
Animal ani = new Cat();
//ani是不是猫类型?是就转型,不是就不转
if(ani instanceof Cat) {
//向下转型
Cat cat = (Cat)ani;
//此时就可以用子类的特有功能
cat.play();
} else {
System.out.println("没有该类型,无法转换");
}
}
}
关于强转前的判断,jdk14以后有新特性:
语法:a instanceof B b
//变量a是不是B类型,如果是,则强转为B类型,转换后的变量名更改为b;如果不是不强转,结果为false
if(ani instanceof Cat cat) {
cat.play();
} else {
System.out.println("没有该类型,无法转换");
}