多态
1. 什么是多态?
多态:事物的多种形态
2. 多态的表现形式?
- 父类类型 对象名称 = 子类对象;
- Fu f = new zi();
- 把子类对象赋值给父类类型的变量
3. 多态的前提?
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法的重写(可选的)
4. 多态的好处?
- 方法中使用父类类型作为参数,可以接收父类对象 + 所有子类对象
- 如果进行方法重写,利用多态调用方法,可以调用不同子类中重写的方法(取决于你在方法中传入的子类对象)
5.多态调用成员的特点
- 变量调用:编译时看左边,运行时看左边 (始终看父类引用类型,不具备多态)
- 方法调用:编译时看左边,运行时看右边(正因为运行时看的是右边的子类对象,所有方法具备多态,不同对象执行不同方法,配合上方法重写,执行不同对象的不同方法体,前提是父类中也要有该方法,否则编译会报错。除非你对父类进行强制类型转换,引用类型变成子类后,编译阶段就直接去子类中寻找该方法体,)
变量与方法在调用层面的对比:
成员变量
- 编译看左边
- 运行看左边
→ 全程看引用类型,不具备多态
成员方法
- 编译看左边(在父类中检查方法是否存在)
- 运行看右边(执行实际对象(右边的子类对象)的方法)
→ 具备多态
6.因为多态用的是「父类引用」,编译器只认引用的类型,不认实际对象的类型。
编译器编译时:
- 只知道 animal 是 Animal 类型
- 不知道它将来会指向 Dog、Cat 还是别的子类
- 所以它只允许你调用 Animal 类里明确写了的方法
bark() 是 Dog 独有的,Animal 里没有,编译器直接拒绝。
多态下,成员变量不参与多态,访问谁的变量,完全看引用类型,跟实际对象无关。
class Father {
String name = "父亲";
}
class Son extends Father {
String name = "儿子"; // 子类同名变量
}
多态写法:
Father obj = new Son();
System.out.println(obj.name);
输出结果是:父亲
为什么?
1. 成员变量没有 “重写”,只有 “隐藏”
- 方法重写:运行时看实际对象
- 变量:编译时就定死了,看引用类型
Father obj
→ 编译器认为 obj 是 Father
→ 直接访问 Father 的 name
跟你 new 的是 Son 没关系。
结论
- 方法:多态生效,运行看对象
- 变量:多态无效,编译看引用
和方法一样:
父类里没有的变量,父类引用根本访问不到。
7.多态的弊端是什么?
不能使用子类特有的功能,因为调用方法的时候,编译看的是左边,如果是子类特有的方法,那么编译时父类找不到方法会报错
8.引用数据类型的类型转换,有几种方式?
- 自动类型转换(向上转型,把小的变成大的)
- 强制类型转换(向下转型,把大的变成小的)
9.强制类型转换能解决什么问题?强制类型转换需要注意什么?
- 可以转换成真正的子类类型,从而调用子类独有功能。
- 转换类型(父类类型)与真实对象类型(子类类型)不一致会报错
- 转换的时候用instanceof关键字进行判断
语法:对象 instanceof **类型
1. 类型向下转型前的安全校验
父类引用指向子类对象时,强制向下转型容易类型转换异常,必须先用instanceof判断
Animal animal = new Dog(); // 父类引用指向子类对象
// 安全向下转型
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 转型不会报错
dog.bark();
2. 多态场景下区分不同子类
同一个父类的多个子类,需要根据实际类型执行不同逻辑。
public void feed(Animal animal) {
if (animal instanceof Dog) {
System.out.println("喂狗粮");
} else if (animal instanceof Cat) {
System.out.println("喂猫粮");
}
}
}
作用:基于对象实际类型做分支处理。
浙公网安备 33010602011771号