三 多态
1 多态的概述
1.1 什么是多态?
多态是面向对象编程的三大特性之一(封装、继承、多态),指的是同种类型的对象,在不同情况下表现出不同形态的能力。
多态的应用场景: 学生管理系统中,注册模块需要分教师、学生等
多态: 类型的多种形态(同种类型的对象,表现出的不同形态)
1.2 多态的表现形式
父类类型 对象名称 = new 子类对象();1.3 多态的前提条件
✅ 有继承/实现关系
✅ 有父类引用指向子类对象
Fu f = new Zi();✅ 有方法重写(体现不同形态)
1.4 多态的优势
多态的好处: 使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性与遍历
1.5 多态的实现练习:
//Person.java
package com.yq.a01polymorephismdemo01;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show() {
System.out.println(name + ", " + age);
}
}
//Student.java
package com.yq.a01polymorephismdemo01;
public class Student extends Person{
@Override
public void show() {
System.out.println("学生的信息为: " + getName() + ", " + getAge());
}
}
//Teacher.java
package com.yq.a01polymorephismdemo01;
public class Teacher extends Person{
@Override
public void show() {
System.out.println("老师的信息为: " + getName() + ", " + getAge());
}
}
//Administrator.java
package com.yq.a01polymorephismdemo01;
public class Administrator extends Person{
@Override
public void show() {
System.out.println("管理员的信息为: " + getName() + ", " + getAge());
}
}
//Test.java
package com.yq.a01polymorephismdemo01;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("zhangsan");
s.setAge(18);
Teacher t = new Teacher();
t.setName("lisi");
t.setAge(30);
Administrator admin = new Administrator();
admin.setName("admin");
admin.setAge(35);
register(s);
register(t);
register(admin);
}
//这个方法既能接受老师 又能接受学生 还能接受管理员
//只能把参数写成这三个类型的父类
public static void register(Person p){
p.show();
}
}
2 多态调用成员的特点
变量调用: 编译看左边,运行也看左边 方法调用: 编译看左边,运行看右边
2.1 调用练习
package com.yq.a02polymorephismdemo02;
public class Test {
public static void main(String[] args) {
//创建对象(多态的方式)
//Fu f = new Zi();
Animal a = new Dog();
//调用成员变量: 编译看左边, 运行看左边
//编译看左边: javac编译代码时,会看左边的父类中有没有这个变量 如果有则编译成功 如果没有则编译失败
//运行也看左边: java运行代码时, 实际获取的就是左边父类中成员变量的值
System.out.println(a.name);
//调用成员方法: 编译看左边, 运行看右边
//编译看左边: javac编译代码时,会看左边的父类中有没有这个方法 如果有则编译成功 如果没有则编译失败
//运行看右边: java运行代码时, 实际运行的是右边子类中成员方法
a.show();
//理解:
//Animal a = new Dog();
//用a调用变量和方法, 而a是Animal类型,所以默认会从Animal这个类中去找
//成员变量:在子类的对象中,会把父类的成员变量往下继承 父name 子name
//成员方法:如果子类对方法进行了重写,那么在虚方法中会把这个父类的方法进行覆盖
}
}
class Animal {
String name = "动物";
public void show(){
System.out.println("Animal -- show方法");
}
}
class Dog extends Animal{
String name = "狗";
@Override
public void show() {
System.out.println("Dog --- show方法");
}
}
class Cat extends Animal{
String name = "猫";
@Override
public void show() {
System.out.println("Cat --- show方法");
}
}2.1 成员变量调用
规则:编译看左边,运行也看左边
Animal a = new Dog();
System.out.println(a.name); // 输出"动物",不是"狗"解释:
编译看左边:检查父类中是否有该变量
运行看左边:实际获取父类成员变量的值
2.2 成员方法调用
规则:编译看左边,运行看右边
Animal a = new Dog();
a.show(); // 输出"Dog --- show方法",不是"Animal -- show方法"解释:
编译看左边:检查父类中是否有该方法
运行看右边:实际运行子类重写后的方法
2.3 内存原理

3 多态的优势
在多态形势下,右边对象可以实现解耦合,便于扩展和维护
3.1 优势
// 业务逻辑稳定,即使对象类型变化也不影响
Person p = new Student();
p.work(); // 业务逻辑变更时,此代码无需修改3.2 弊端
不能调用子类特有的方法
Animal a = new Dog();
// a.lookHome(); // 编译错误!父类没有此方法3.3 解决方案:类型转换
方式一:传统类型判断与转换
if (a instanceof Dog) {
Dog d = (Dog) a;
d.lookHome();
} else if (a instanceof Cat) {
Cat c = (Cat) a;
c.catchMouse();
}方式二:JDK14+新特性
if (a instanceof Dog d) {
d.lookHome(); // 自动转换并赋值
} else if (a instanceof Cat c) {
c.catchMouse(); // 自动转换并赋值
}定义方法时,使用父类型作为参数,可以接受所有子类对象,体现多态的扩展性与便利
练习:
package com.yq.a03polymorephismdemo03;
import com.sun.security.jgss.GSSUtil;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//创建对象
Animal a = new Dog();
//编译看左边 运行看右边
a.eat();
//多态的弊端: 不能调用子类特有的方法
//编译看左边 父类没有lookHome 直接报错
//a.lookHome(); //会报错
//解决方案: 变回子类型
//Dog d = (Dog) a;
//d.lookHome();
//细节: 转换的时候不能瞎转, 如果转成其他类的类型, 就会报错
/* a对象创建为的是 Dog类型,而Dog类型中没有catchMouse
Cat c = (Cat) a;
c.catchMouse();
*/
//instanceof判断对象的类型, 再进行转换
/*
if(a instanceof Dog){
Dog d = (Dog) a;
d.lookHome();
} else if (a instanceof Cat){
Cat c = (Cat) a;
c.catchMouse();
} else {
System.out.println("没有这个类型, 无法转换");
}
*/
//新特性
//先判断a是否为Dog类型,如果是则强转成Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if(a instanceof Dog d){
d.lookHome();
} else if (a instanceof Cat c){
c.catchMouse();
} else {
System.out.println("没有这个类型, 无法转换");
}
}
}
class Animal {
public void eat(){
System.out.println("动物在吃东西");
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
public void lookHome(){
System.out.println("狗看家");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃小鱼干");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}4 多态练习

多态练习需求:
根据需求完成代码:
1.定义狗类
属性:
年龄,颜色
行为:
eat(String something)(something表示吃的东西)
看家lookHome方法(无参数)
2.定义猫类
属性:
年龄,颜色
行为:
eat(String something)方法(something表示吃的东西)
逮老鼠catchMouse方法(无参数)
3.定义Person类//饲养员
属性:
姓名,年龄
行为:
keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:
keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
生成空参有参构造,set和get方法
4.定义测试类(完成以下打印效果):
keepPet(Dog dog,String somethind)方法打印内容如下:
年龄为30岁的老王养了一只黑颜色的2岁的狗
2岁的黑颜色的狗两只前腿死死的抱住骨头猛吃
keepPet(Cat cat,String somethind)方法打印内容如下:
年龄为25岁的老李养了一只灰颜色的3岁的猫
3岁的灰颜色的猫眯着眼睛侧着头吃鱼
5.思考:
1.Dog和Cat都是Animal的子类,以上案例中针对不同的动物,定义了不同的keepPet方法,过于繁琐,能否简化,并体会简化后的好处?
2.Dog和Cat虽然都是Animal的子类,但是都有其特有方法,能否想办法在keepPet中调用特有方法?需求分析:
设计一个饲养员喂养不同动物的系统,体现多态的优势。
类结构设计:
Animal(父类)
├── Dog(子类)
└── Cat(子类)
Person(饲养员类)实现代码:
//Animal.java
package com.yq.a04polymorephismdemo04;
public class Animal {
private int age;
private String color;
public Animal() {
}
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(String something) {
System.out.println("动物在吃" + something);
}
}
//Dog.java
package com.yq.a04polymorephismdemo04;
public class Dog extends Animal {
public Dog() {
}
public Dog(int age, String color) {
super(age, color);
}
//行为
@Override
public void eat(String something) {
System.out.println(getAge() + " 岁的 " + getColor() + " 颜色的狗两只前腿死死的抱住 " + something + " 猛吃");
}
public void lookHome() {
System.out.println("狗在看家");
}
}
//Cat.java
package com.yq.a04polymorephismdemo04;
public class Cat extends Animal {
public Cat() {
}
public Cat(int age, String color) {
super(age, color);
}
@Override
public void eat(String something) {
System.out.println(getAge() + " 岁的" + getColor() + " 颜色的猫眯着眼睛侧着头吃 " + something);
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
//Person.java
package com.yq.a04polymorephismdemo04;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*
public void keepPet(Dog dog, String something) {
System.out.println("年龄为 " + age + " 岁的" + name + "养了一只 " + dog.getColor() + " 颜色的 " + dog.getAge() + " 岁的狗");
dog.eat(something);
}
public void keepPet(Cat cat, String something) {
System.out.println("年龄为 " + age + " 岁的 " + name + " 养了一只 " + cat.getColor() + " 颜色的 " + cat.getAge() + " 岁的猫");
cat.eat(something);
}
*/
public void keepPet(Animal a, String something) {
if (a instanceof Dog d) {
System.out.println("年龄为 " + getAge() + " 岁的" + getName() + "养了一只 " + d.getColor() + " 颜色的 " + d.getAge() + " 岁的狗");
d.eat(something);
} else if (a instanceof Cat c) {
System.out.println("年龄为 " + getAge() + " 岁的" + getName() + "养了一只 " + c.getColor() + " 颜色的 " + c.getAge() + " 岁的狗");
c.eat(something);
} else {
System.out.println("没有这个动物");
}
}
}//Test.java
package com.yq.a04polymorephismdemo04;
public class Test {
public static void main(String[] args) {
/*
Person p1 = new Person("老王", 30);
Dog d = new Dog(2, "黑");
p1.keepPet(d, "骨头");
Person p2 = new Person();
p2.setName("老李");
p2.setAge(25);
Cat c = new Cat();
c.setAge(3);
c.setColor("灰");
p2.keepPet(c, "鱼");
*/
//升级版
//创建饲养员对象
Person p1 = new Person("老王", 30);
Animal d = new Dog(2, "黑");
p1.keepPet(d,"骨头");
Person p2 = new Person();
p2.setName("老李");
p2.setAge(25);
Animal c = new Cat();
c.setAge(3);
c.setColor("灰");
p2.keepPet(c,"鱼");
}
}5 多态总结
1.多态的优势:
方法中,使用父类型作为参数,可以接受所有子类对象
2.多态的弊端:
不能使用子类的特有功能
3.引用数据类的类型转换,有几种方式
自动类型转换、强制转换
Person p = new Student(); //自动类型转换
Student s = (Student)p; //强制类型转换
4.强制类型转换能解决什么问题
可以转换成真正的子类类型,从而调用子类独有功能
转换类型与真实对象类型不一致会报错
转换的时候建议使用instanceof关键字进行判断
评论区