多态
什么是多态
在继承父类或者实现接口的基础上,允许同一类事物出现不同的状态
多态的前提:继承或实现的关系、方法的重写、父类(接口)引用指向子类(实现类)对象
表现形式
父类 变量 = 子类对象();
接口 变量 = 实现对象();
需求:
- 定义Animal动物类作为父类,规定吃饭、喝水功能。
- 定义子类Dog和Cat,分别创建Dog对象和Cat对象,调用吃饭功能和喝水功能
思考:
1.定义Animal动物类,作为父类
2.定义Dog狗类和Cat猫类,作为子类
3.分别创建Dog和Cat对象,调用吃饭、喝水功能
/**
* 动物类,作为父类的
*/
public abstract class Animal {
//喝水
public void drink() {
System.out.println("喝水");
}
//吃饭
public abstract void eat();
}
/**
* 猫类
*/
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
/**
* 狗类,作为子类
*/
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
之前的想法:
Dog dog = new Dog();
Cat cat = new Cat();
引入多态的思想:
//允许将子类对象,给父类类型变量赋值
//将dog和cat变量变成同一类型
Animal dog = new Dog();
Animal cat = new Cat();
//呈现相同状态
dog.drink();
cat.drink();
//呈现不同状态
dog.eat();
cat.eat();
多态关系中,成员的访问特点
目标:了解多态中成员的访问特点
- 方法调用:编译看左边,运行看右边
- 变量调用:编译看左边,运行也看左边
需求:有父类Fu和子类Zi,请使用多态的形式创建对象并访问各自属性和方法
//父类
public class Fu {
String field = "父类属性";
public void method() {
System.out.println("父类方法");
}
}
//子类
public class Zi extends Fu {
String field = "子类属性";
String ziField = "子类特有属性";
public void method() {
System.out.println("子类方法");
}
public void ziMethod() {
System.out.println("子类特有方法");
}
}
public static void main(String[] args) {
/**
* 多态中成员访问特点:
* 变量调用:编译看左边,运行也看左边
* 方法调用:编译看左边,运行看右边
*
* 需求:有父类Fu和子类Zi,请使用多态的形式创建对象并访问各自属性和方法
*/
//1.用多态的代码形式创建Zi对象,给Fu类型变量赋值
Fu zi = new Zi();
//2.访问父类和子类都有(同名)的属性
System.out.println(zi.field);
//结果: 父类属性
//3.访问父类没有但子类有的属性
//System.out.println(zi.ziField);
//报错
//访问变量:编译看左边,运行也看左边
System.out.println("-------------------");
//4.访问父类和子类都有(同名)的方法
zi.method();
//结果: 子类方法
//5.访问父类没有但子类有的方法
//zi.ziMethod();
//报错
//访问方法:编译看左边,运行看右边
}
多态好处与弊端
优势:解耦合,提高方法的扩展性,把方法的形参写成父类/接口类型,调用方法的时候可以传递子类/实现类对象
劣势:多态下不能使用子类的特有功能
需求:利用多态技术优化useDog和useCat方法,使两个方法变为一个方法!
public abstract class Animal {
public void drink() {
System.out.println("喝水!");
}
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//猫类特有功能:抓老鼠
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
//狗类特有功能:狗看家
public void lookHome() {
System.out.println("狗看家");
}
}
public static void main(String[] args) {
feedAnimal(new Dog());
feedAnimal(new Cat());
}
public static void feedAnimal(Animal animal) {
animal.eat();
//2.尝试访问子类的特有功能,失败报错
//访问:狗看家
//animal.lookHome();
//访问:猫抓老鼠
//animal.catchMouse();
//多态的弊端:在多态形式下,不能访问子类的特有功能
}
多态的转型
目标:了解多态下引用数据类型的类型转换操作
多态转型指的是:把父类类型强制转换为子类类型
格式:子类 变量 = (子类)被转换的数据;
原本是什么类型,才能还原为什么类型
Animal a = new Dog();
Dog d = (Dog)a;
instanceof关键字
作用:测试它左边的对象是否是它右边的类的实例
if( a instanceof Dog ){
Dog d = (Dog)a;
d.lookHome();
}
目标:了解多态下引用数据类型的类型转换操作
public static void useAnimal(Animal animal) {
animal.eat();
//1.强转成Dog狗类型
//Dog dog = (Dog) animal;
//调用狗的特有功能
//dog.lookHome();
//2.正确的强转方案:先判断,后强转。使用instanceof
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.lookHome();
}
//3.在高版本的jdk中,上面的代码可以进一步简化
if (animal instanceof Cat cat) {
cat.catchMouse();
}
}
小结
- 多态的形式有表现形式有两种
父类变量接收__子类对象
接口变量接收__实现类对象 - 多态的好处是什么?
如果方法的参数是父类类型,那么调用方法可以传递子类对象
如果方法的参数是接口类型,那么调用方法可以传递实现类对象______ - 多态的弊端是什么?
在多态的情况下,不能调用子类或者实现类的_特有方法