侧边栏壁纸
博主头像
青菜-halo2 博主等级

行动起来,活在当下

  • 累计撰写 74 篇文章
  • 累计创建 6 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

14-面向对象进阶_02(多态)

Administrator
2025-10-24 / 0 评论 / 4 点赞 / 41 阅读 / 0 字

三 多态

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 内存原理

image-20251023112550274.png

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 多态练习

多态练习的分析.png

多态练习需求:

根据需求完成代码:
	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关键字进行判断

5.1 核心要点

特性

说明

示例

定义

同一行为的不同表现形态

Animal a = new Dog()

前提

继承 + 父类引用 + 方法重写

必须满足三个条件

变量调用

编译看左,运行看左

获取父类变量值

方法调用

编译看左,运行看右

执行子类重写方法

5.2 类型转换总结

转换类型

方式

说明

自动转换

父类 变量 = new 子类()

向上转型,安全

强制转换

子类 变量 = (子类)父类变量

向下转型,需判断类型

类型判断

instanceof

转换前必须判断,避免ClassCastException

4

评论区