20260724-笔记.md 12 KB

JavaSE 基础 — Day10 笔记

日期:2026-07-24
项目c260724
作者:WanJL


一、多态(Polymorphism)

1.1 什么是多态

面向对象三大特征之一(封装、继承、多态)。
同一个对象,在不同时刻表现出来的不同形态。

例如:

  • 学生 张三Student 类型
  • Student extends Person,则张三同时具备 StudentPerson 两种形态
  • Person extends Animal,则张三具备 StudentPersonAnimal 三种形态

核心理解:一个对象可以拥有多种类型身份,通过父类/接口的引用指向子类/实现类的对象。


1.2 多态的前提条件

条件 说明
① 继承或实现关系 子类 extends 父类,或实现类 implements 接口
② 方法重写 子类/实现类必须重写父类/接口的方法
③ 父类引用指向子类对象 Animal a = new Dog();
// 父类引用指向子类对象
Animal animal = new Dog();
animal.eat();
animal.sleep();

📄 来源:Test01.java


1.3 多态中成员的访问特点

成员类型 编译时期 运行时期
成员变量 看父类 看父类(没有多态)
成员方法 看父类(需存在) 看子类(重写后执行子类)

口诀:编译看左边,运行看右边(针对方法而言)。

// 仅能调用父类中声明的方法
Animal animal = new Dog();
animal.eat();   // ✅ 编译看父类有 eat(),运行执行 Dog 的 eat()
animal.sleep(); // ✅ 编译看父类有 sleep()(抽象),运行执行 Dog 的 sleep()
// animal.wangWang(); // ❌ 编译报错,父类没有 wangWang()

📄 来源:Test01.javaDog.java


1.4 多态的好处——提高代码扩展性

多态让代码对扩展开放,对修改关闭(开闭原则)。

典型应用:笔记本 USB 接口案例

// Usb 接口
public interface Usb {
    void startUsb();
    void stopUsb();
}

// 笔记本类——接收任意 Usb 实现类
public class NoteBook {
    public void useUsb(Usb usb) {   // 参数类型为 Usb 接口
        usb.startUsb();
        System.out.println("开始工作.....");
        usb.stopUsb();
    }
}

// 鼠标实现 Usb
public class Mouse implements Usb {
    public void startUsb() { System.out.println("USB鼠标开启"); }
    public void stopUsb()  { System.out.println("USB鼠标关闭"); }
}

📄 来源:Usb.javaNoteBook.javaMouse.java

// 测试多态
NoteBook noteBook = new NoteBook();
Usb mouse = new Mouse();
noteBook.useUsb(mouse);   // ✅ 传入鼠标

Usb cat = new Cat();      // ✅ 猫也能实现 Usb(示例演示)
noteBook.useUsb(cat);     // ✅ 传入猫 USB

📄 来源:Test02.java

关键点NoteBook.useUsb(Usb usb) 的参数是接口类型,任何实现 Usb 接口的类都可以传入,无需修改笔记本代码即可扩展新设备。


1.5 多态中的转型

多态涉及两种类型转换:

1.5.1 向上转型(Upcasting)

即"父类的引用指向子类的对象",前面所有示例都属于向上转型。

Person p = new Student();   // ✅ 向上转型
Animal a = new Dog();       // ✅ 向上转型
Usb mouse = new Mouse();    // ✅ 向上转型(接口)

1.5.2 向下转型(Downcasting)

概念:将父类引用 强制转换 为子类引用,恢复子类对象的完整形态。

格式

子类类型 对象名 = (子类类型) 父类引用名;

前提:必须先执行向上转型。

// 1、先向上转型
Person p = new Student();
// 2、再向下转型
Student s = (Student) p;   // ✅ 强制转换

为什么需要向下转型?

  • 向上转型后,父类引用只能调用父类中声明的方法,无法调用子类的特有方法
  • 若需调用子类特有方法(如 study()play()),必须向下转型

    Person p = new Student();
    p.eat();    // ✅ 父类中有 eat()
    p.sleep();  // ✅ 父类中有 sleep()
    // p.study(); // ❌ 编译报错!父类中没有 study()
    
    Student s = (Student) p;   // 向下转型
    s.study();  // ✅ 转型后可以调用子类特有方法
    

📄 来源:Demo02.java

1.5.3 instanceof 运算符——类型判断

问题:向下转型前,如何确定父类引用指向的是哪个子类对象?直接强转可能引发 ClassCastException

解决:使用 instanceof 运算符进行类型判断。

格式 说明
对象名 instanceof 类型 判断左边对象是否属于右边类型
返回 boolean true 表示是,false 表示否
// 生活案例:外卖点餐
public void 点外卖(外卖类 wm) {
    if (wm instanceof 手撕烤鸭类) {
        手撕烤鸭类 ssky = (手撕烤鸭类) wm;
        ssky.准备塑料手套();
    } else if (wm instanceof 麻辣烫类) {
        麻辣烫类 mlt = (麻辣烫类) wm;
        mlt.准备筷子();
    }
}

📄 来源:Demo02.java


1.6 综合案例:runPerson() 方法

将多态、instanceof、向下转型三者结合使用:

public class Test03 {
    // 参数为抽象父类类型——多态的体现
    public void runPerson(Person p) {
        p.eat();    // ✅ 编译看Person,运行看子类

        // 判断 p 指向的具体子类类型
        if (p instanceof Student) {
            Student s = (Student) p;   // 向下转型
            s.study();                 // 调用子类特有方法
        } else if (p instanceof Teacher) {
            Teacher t = (Teacher) p;   // 向下转型
            t.play();                  // 调用子类特有方法
        }

        p.sleep();  // ✅ 编译看Person,运行看子类
    }

    public static void main(String[] args) {
        Test03 t = new Test03();
        t.runPerson(new Student());   // 向上转型传入 Student
        t.runPerson(new Teacher());   // 向上转型传入 Teacher
    }
}

📄 来源:Test03.java

执行流程分析(以传入 new Student() 为例):

runPerson(new Student())
  ─→ p.eat()               → 输出 "学生吃饭..."
  ─→ p instanceof Student  → true → (Student)p → s.study() → 输出 "学生学习..."
  ─→ p.sleep()             → 输出 "学生睡觉..."

二、抽象类回顾与多态结合

2.1 抽象类定义

public abstract class Animal {
    public void eat() {              // 普通方法
        System.out.println("动物吃饭.....");
    }
    public abstract void sleep();    // 抽象方法
}

📄 来源:Animal.java

2.2 子类继承抽象类

public class Dog extends Animal {
    @Override
    public void sleep() {
        System.out.println("小狗睡觉....");
    }
    @Override
    public void eat() {
        System.out.println("小狗吃饭....");
    }
    public void wangWang() {
        System.out.println("小狗汪汪....");
    }
}

📄 来源:Dog.java

  • 子类必须重写父类的所有抽象方法(除非子类也是抽象类)
  • 子类可以重写父类的普通方法(eat()
  • 子类可以扩展自己的特有方法(wangWang()

2.3 另一组示例:Person → Student / Teacher

// 抽象父类
public abstract class Person {
    public abstract void eat();
    public abstract void sleep();
}

// 子类 Student
public class Student extends Person {
    @Override
    public void eat()  { System.out.println("学生吃饭..."); }
    @Override
    public void sleep(){ System.out.println("学生睡觉..."); }
    public void study(){ System.out.println("学生学习..."); }  // 特有方法
}

// 子类 Teacher
public class Teacher extends Person {
    @Override
    public void eat()  { System.out.println("教师吃饭..."); }
    @Override
    public void sleep(){ System.out.println("教师睡觉..."); }
    public void play() { System.out.println("教师玩....爽...."); }  // 特有方法
}

📄 来源:Person.javaStudent.javaTeacher.java


三、接口多态案例(USB接口 + 笔记本)

3.1 接口定义

public interface Usb {
    void startUsb();   // 抽象方法(默认 public abstract)
    void stopUsb();
}

📄 来源:Usb.java

3.2 实现 Usb 接口的设备

// 鼠标实现 Usb 接口
public class Mouse implements Usb {
    @Override
    public void startUsb() {
        System.out.println("USB鼠标开启");
    }
    @Override
    public void stopUsb() {
        System.out.println("USB鼠标关闭");
    }
}

// Cat 也实现 Usb 接口(演示用:任何类都可以实现接口)
public class Cat implements Usb {
    @Override
    public void startUsb() { }
    @Override
    public void stopUsb() { }
}

📄 来源:Mouse.javaCat.java

3.3 笔记本接入设备——多态参数的应用

// 笔记本——方法参数为 Usb 接口类型
public class NoteBook {
    public void useUsb(Usb usb) {   // 📌 接口类型参数 —— 多态的体现
        usb.startUsb();
        System.out.println("开始工作.....");
        usb.stopUsb();
    }
}

📄 来源:NoteBook.java

3.4 测试多态

public class Test02 {
    public static void main(String[] args) {
        NoteBook noteBook = new NoteBook();

        Usb mouse = new Mouse();        // ✅ 接口引用指向实现类对象
        noteBook.useUsb(mouse);         // 传入鼠标

        Usb cat = new Cat();            // ✅ 猫也实现了 Usb
        noteBook.useUsb(cat);           // 传入猫 USB
    }
}

📄 来源:Test02.java

关键点NoteBook.useUsb(Usb usb) 的参数类型是 接口,任何实现 Usb 接口的类都可以传入,无需修改笔记本的代码即可接入新设备——这就是 多态提高扩展性 的典型应用。


四、随堂练习要点

练习方向 涉及知识点 对应文件
多态入门 多态前提、父类引用指向子类对象、成员访问特点 Test01.javaDog.java
多态中的转型 向上转型、向下转型、instanceof 运算符 Demo02.javaTest03.java
抽象类多态综合 抽象父类 Person、多态参数、向下转型调特有方法 Test03.javaPerson.java
接口多态 Usb 接口、笔记本接入多设备 Test02.javaNoteBook.java

五、拓展阅读 & 常见面试题

  1. 多态的实现原理——Java 中多态是通过动态绑定(后期绑定)实现的,JVM 在运行时根据对象的实际类型调用对应的方法。
  2. 多态与继承的关系——多态是基于继承或接口实现的。
  3. 多态的优势——提高代码的可扩展性和可维护性,符合开闭原则(对扩展开放,对修改关闭)。
  4. 向下转型的风险——向下转型必须配合 instanceof 判断,否则可能抛出 ClassCastException(类型转换异常)。
  5. instanceof 的用法——常用于向下转型前的安全判断,避免强制类型转换异常。

六、今日知识图谱

面向对象三大特征
├── 封装(private / getter / setter)
├── 继承(extends / super / @Override)
└── 多态 ⭐(今日重点)
    ├── 前提:继承/实现 + 重写 + 父类引用指向子类对象
    ├── 成员访问:编译看左边,运行看右边
    ├── 多态中的转型
    │   ├── 向上转型(Upcasting)
    │   │   └── 父类引用指向子类对象:Person p = new Student();
    │   ├── 向下转型(Downcasting)
    │   │   ├── 格式:子类类型 对象名 = (子类类型) 父类引用;
    │   │   ├── 前提:必须先向上转型
    │   │   └── 用途:调用子类特有方法
    │   └── instanceof 运算符
    │       └── 格式:对象名 instanceof 类型(返回 boolean)
    └── 多态的好处:提高扩展性(开闭原则)
        └── 案例:NoteBook.useUsb(Usb usb)