20260724-笔记.md 9.5 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 接口的类都可以传入,无需修改笔记本代码即可扩展新设备。


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

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()

三、接口多态与接口新特性(JDK8+)

3.1 接口定义

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

📄 来源:Usb.java

3.2 接口默认方法(JDK 8)

在接口中定义带方法体的方法,使用 default 关键字。实现类可以选择重写或不重写。

public interface Notifiable {
    // 抽象方法——实现类必须重写
    void doSend(String recipient, String message);

    // 默认方法——校验参数(实现类可选重写)
    default boolean validateParams(String recipient, String message) {
        if (recipient != null && message != null && !recipient.isEmpty() && !message.isEmpty()) {
            System.out.println("参数校验通过");
            return true;
        }
        System.out.println("参数校验失败:收件人或消息不能为空");
        return false;
    }

    // 默认方法——记录日志(实现类可选重写)
    default void log(String level, String msg) {
        System.out.println("[" + level + "]消息:" + msg);
    }
}

📄 来源:Notifiable.java

3.3 接口静态方法(JDK 8)

使用 static 关键字定义,通过接口名直接调用。

public interface Notifiable {
    static void printNotificationType() {
        System.out.println("通知系统 v1.0——支持邮件/短信/微信通知");
    }
}

// 调用方式
Notifiable.printNotificationType();

📄 来源:Notifiable.javaTestNotification.java


四、模板方法设计模式(基于接口默认方法)

在接口中定义一个 默认方法 作为模板,规定固定的算法流程,让实现类只需关注核心业务逻辑。

public interface Notifiable {
    // 模板方法——定义固定的发送流程
    default void send(String recipient, String message) {
        // 1、校验参数
        boolean boo = validateParams(recipient, message);
        if (boo) {
            // 2、执行发送(调用抽象方法,由实现类完成具体逻辑)
            doSend(recipient, message);
            // 3、记录日志
            log("INFO", "发送成功");
            System.out.println("--- 发送流程结束 ---");
        }
    }
}

📄 来源:Notifiable.java

流程示意图

send()  →  validateParams()  →  doSend()  →  log()  →  完成
(模板)     (默认方法-校验)      (抽象方法)    (默认方法)

五、课后作业:通知系统(Notifiable 体系)

5.1 接口定义

使用 JDK8 新特性定义通知接口:

  • 抽象方法 doSend()——实现类实现不同的发送逻辑
  • 默认方法 validateParams()——参数校验
  • 默认方法 log()——日志记录
  • 默认方法 send()——模板方法,组合流程
  • 静态方法 printNotificationType()——输出系统信息

5.2 实现类

public class EmailNotifier implements Notifiable {
    @Override
    public void doSend(String recipient, String message) {
        System.out.println("发送邮件给 " + recipient + ":内容 -" + message);
    }
    // 可选重写默认方法 log()
    @Override
    public void log(String level, String msg) {
        System.out.println("[邮件][" + level + "]消息:" + msg);
    }
}

📄 来源:EmailNotifier.java

5.3 测试类

public class TestNotification {
    public static void main(String[] args) {
        // 1、调用接口静态方法
        Notifiable.printNotificationType();
        // 2、创建实现类对象
        EmailNotifier en = new EmailNotifier();
        // 3、正常发送
        en.send("admin@163.com", "系统升级通知");
        // 4、参数为空——触发校验失败
        en.send("", "测试");
    }
}

📄 来源:TestNotification.java


六、随堂练习要点

练习方向 涉及知识点 对应文件
多态入门 多态前提、父类引用指向子类对象、成员访问特点 Test01.javaDog.java
接口多态 Usb 接口、笔记本接入多设备 Test02.javaNoteBook.java
通知系统(作业) 接口默认方法、静态方法、模板方法设计模式 作业包 homework

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

  1. 多态的实现原理——Java 中多态是通过动态绑定(后期绑定)实现的,JVM 在运行时根据对象的实际类型调用对应的方法。
  2. 多态与继承的关系——多态是基于继承或接口实现的。
  3. 多态的优势——提高代码的可扩展性和可维护性,符合开闭原则(对扩展开放,对修改关闭)。
  4. 接口默认方法的用途——在不破坏已有实现类的前提下向接口添加新方法;实现模板方法模式。
  5. 接口静态方法的用途——提供工具方法,接口即命名空间,无需额外工具类。
  6. 模板方法设计模式——定义一个操作中的算法骨架(模板方法),将一些步骤延迟到子类/实现类中实现。

八、今日知识图谱

面向对象三大特征
├── 封装(private / getter / setter)
├── 继承(extends / super / @Override)
└── 多态 ⭐(今日重点)
    ├── 前提:继承/实现 + 重写 + 父类引用指向子类对象
    ├── 成员访问:编译看左边,运行看右边
    ├── 多态的好处:提高扩展性(开闭原则)
    │   └── 案例:NoteBook.useUsb(Usb usb)
    └── 接口多态 + JDK8 新特性
        ├── 默认方法(default)—— 模板方法设计模式
        └── 静态方法(static)—— 接口名直接调用