Java二次分发

java 复制代码
package com.example.demo;

public class UserDemo {
  public static void main(String[] args) {
    Driver a = new FemaleDriver();
    Driver b = new MaleDriver();
    Vehicle x = new Car();
    Vehicle y = new Bus();
    a.drives(x);
    b.drives(y);
  }
}

abstract class Vehicle {
  private String type;
  public Vehicle() {};
  public Vehicle(String s) {
    type = s;
  };
  public abstract void driveByFemaleDriver();
  public abstract void driveByMaleDriver();
}

class Bus extends Vehicle {
  public Bus() {}
  public void driveByFemaleDriver(){
    System.out.println("bus drive by female driver");
  }
  public void driveByMaleDriver() {
    System.out.println("bus drive by male driver");
  }
}

class Car extends Vehicle {
  public Car() {}
  public void driveByFemaleDriver(){
    System.out.println("bus drive by female driver");
  }
  public void driveByMaleDriver() {
    System.out.println("bus drive by male driver");
  }
}

abstract class Driver{
  public Driver() {}
  public abstract void drives(Vehicle v);
}

// 二次分发
class FemaleDriver extends Driver {
  public FemaleDriver() {}
  public void drives(Vehicle v) {
    v.driveByFemaleDriver();
  }
}
class MaleDriver extends Driver {
  public MaleDriver() {}
  public void drives(Vehicle v) {
    v.driveByMaleDriver();
  }
}

这段代码演示了一个经典的设计模式------双分派(Double Dispatch),我来逐层解释:


📐 整体类结构

#mermaid-svg-ik2oUyw5tiUM60vP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ik2oUyw5tiUM60vP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ik2oUyw5tiUM60vP .error-icon{fill:#552222;}#mermaid-svg-ik2oUyw5tiUM60vP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ik2oUyw5tiUM60vP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ik2oUyw5tiUM60vP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ik2oUyw5tiUM60vP .marker.cross{stroke:#333333;}#mermaid-svg-ik2oUyw5tiUM60vP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ik2oUyw5tiUM60vP p{margin:0;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup text .title{font-weight:bolder;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label text{fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label span{color:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster-label span p{background-color:transparent;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster text{fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .cluster span{color:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .nodeLabel,#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel{color:#131300;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .label text{fill:#131300;}#mermaid-svg-ik2oUyw5tiUM60vP .labelBkg{background:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-ik2oUyw5tiUM60vP .classTitle{font-weight:bolder;}#mermaid-svg-ik2oUyw5tiUM60vP .node rect,#mermaid-svg-ik2oUyw5tiUM60vP .node circle,#mermaid-svg-ik2oUyw5tiUM60vP .node ellipse,#mermaid-svg-ik2oUyw5tiUM60vP .node polygon,#mermaid-svg-ik2oUyw5tiUM60vP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ik2oUyw5tiUM60vP .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP g.clickable{cursor:pointer;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-ik2oUyw5tiUM60vP g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-ik2oUyw5tiUM60vP .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-ik2oUyw5tiUM60vP .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-ik2oUyw5tiUM60vP .dashed-line{stroke-dasharray:3;}#mermaid-svg-ik2oUyw5tiUM60vP .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-ik2oUyw5tiUM60vP #compositionStart,#mermaid-svg-ik2oUyw5tiUM60vP .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #compositionEnd,#mermaid-svg-ik2oUyw5tiUM60vP .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #dependencyStart,#mermaid-svg-ik2oUyw5tiUM60vP .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #dependencyStart,#mermaid-svg-ik2oUyw5tiUM60vP .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #extensionStart,#mermaid-svg-ik2oUyw5tiUM60vP .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #extensionEnd,#mermaid-svg-ik2oUyw5tiUM60vP .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #aggregationStart,#mermaid-svg-ik2oUyw5tiUM60vP .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #aggregationEnd,#mermaid-svg-ik2oUyw5tiUM60vP .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #lollipopStart,#mermaid-svg-ik2oUyw5tiUM60vP .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP #lollipopEnd,#mermaid-svg-ik2oUyw5tiUM60vP .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-ik2oUyw5tiUM60vP .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-ik2oUyw5tiUM60vP .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ik2oUyw5tiUM60vP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ik2oUyw5tiUM60vP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ik2oUyw5tiUM60vP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<abstract>>
Vehicle
-String type
+driveByFemaleDriver()
+driveByMaleDriver()
<<abstract>>
Driver
+drives(Vehicle v)
Bus
Car
FemaleDriver
MaleDriver


🔍 逐段解析

第一层:抽象类 Vehicle(载具)

java 复制代码
abstract class Vehicle {
    private String type;
    public Vehicle() {};
    public Vehicle(String s) { type = s; }

    // 定义两个抽象方法:谁来开,由子类实现
    public abstract void driveByFemaleDriver();
    public abstract void driveByMaleDriver();
}
  • abstract 表示这是抽象类,不能直接 new
  • 声明了两个抽象方法,强制子类(Car、Bus)必须实现

第二层:Car 和 Bus 实现具体行为

java 复制代码
class Bus extends Vehicle {
    public void driveByFemaleDriver() {
        System.out.println("bus drive by female driver");
    }
    public void driveByMaleDriver() {
        System.out.println("bus drive by male driver");
    }
}

class Car extends Vehicle {
    // 同理,实现自己的驾驶行为
}

第三层:抽象类 Driver(司机)

java 复制代码
abstract class Driver {
    public abstract void drives(Vehicle v);  // 接收一个载具
}

第四层:FemaleDriver 和 MaleDriver 实现分派

java 复制代码
class FemaleDriver extends Driver {
    public void drives(Vehicle v) {
        v.driveByFemaleDriver();  // 调用载具上"女性驾驶"方法
    }
}

class MaleDriver extends Driver {
    public void drives(Vehicle v) {
        v.driveByMaleDriver();    // 调用载具上"男性驾驶"方法
    }
}

第五层:主方法执行

java 复制代码
Driver a = new FemaleDriver();
Driver b = new MaleDriver();
Vehicle x = new Car();
Vehicle y = new Bus();

a.drives(x);  // FemaleDriver.drives(Car)  → Car.driveByFemaleDriver()
b.drives(y);  // MaleDriver.drives(Bus)    → Bus.driveByMaleDriver()

🎯 核心:什么是双分派?

Java 本身只支持单分派 (只根据调用者的类型决定执行哪个方法),但这段代码通过两次多态调用模拟了双分派:

复制代码
第一次分派:根据 Driver 的实际类型(Female / Male)
     ↓
a.drives(x)  →  FemaleDriver.drives()

第二次分派:根据 Vehicle 的实际类型(Car / Bus)
     ↓
v.driveByFemaleDriver()  →  Car.driveByFemaleDriver()

用表格表示最终会调用哪个方法:

Car Bus
FemaleDriver Car.driveByFemaleDriver() Bus.driveByFemaleDriver()
MaleDriver Car.driveByMaleDriver() Bus.driveByMaleDriver()

💡 这个模式解决了什么问题?

不用双分派的写法(反例):

java 复制代码
// ❌ 用 if-else 判断类型,难以扩展
public void drives(Vehicle v) {
    if (v instanceof Car) {
        System.out.println("female drives car");
    } else if (v instanceof Bus) {
        System.out.println("female drives bus");
    }
    // 每次新增车辆类型都要修改这里 ❌
}

用双分派的写法:

java 复制代码
// ✅ 新增一种车辆,只需新建子类并实现两个方法,无需改动 Driver
class Truck extends Vehicle {
    public void driveByFemaleDriver() { ... }
    public void driveByMaleDriver() { ... }
}

📝 总结

概念 说明
抽象类 Vehicle 和 Driver 定义骨架,不能直接实例化
多态 父类引用指向子类对象(Driver a = new FemaleDriver())
双分派 通过两次虚方法调用,根据司机类型 + 载具类型共同决定最终行为
设计目的 避免 instanceof 判断,新增类型时只需扩展,不修改已有代码(开闭原则)
相关推荐
paopaokaka_luck33 分钟前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts
阿里嘎多学长41 分钟前
2026-10-12 GitHub 热点项目精选
开发语言·程序员·github·代码托管
Wang's Blog1 小时前
Java 项目实战: 交友项目 - Dubbo 的内部结构与一次调用的完整链路
java·dubbo
Wang's Blog1 小时前
Java 项目实战: 交友项目 - Dubbo 入门引导
java·dubbo·交友
wangchunyu1142 小时前
Python 数据可视化实战入门教程
开发语言·python·信息可视化
蜗牛互联网2 小时前
Python Agent工具调用的白名单、参数校验与审批门禁
java·服务器·前端·人工智能·后端·python
Nil2082 小时前
leetcode 198打家劫舍
算法·leetcode·职场和发展
SL_staff2 小时前
当规则引擎开始‘懂业务’:JVS-Rules金融风控四大原生能力拆解
java·python·全栈
Shaoshing2 小时前
前缀和与差分
java·数据结构·算法·前缀和·差分
dd聊技术2 小时前
Prompt 从代码常量搬进数据库:改一句话,不用再发一次版
java·后端