Java实现简易银行账户管理系统

news2025/1/23 14:33:28

目录

1、项目概述

1.1 项目结构

1.2 技术栈

2、核心功能说明

2.1 账户管理

2.2 异常处理体系

3、设计理念解析

3.1 面向对象设计

3.2 关键设计点

4、使用指南

4.1 运行流程

4.2 注意事项

5、扩展建议

5.1增加功能

5.2优化方向

6、主要的功能模块代码说明

6.1exception

6.2main

6.3model

6.4utils

7、项目反思

7.1基础设计思路是通用的

7.2框架层面:这是“玩具级”,但能训练核心思维

7.3结论:这是合格的“起点”

1、项目概述

1.1 项目结构

完整代码文件

说明:bin和src的代码目录是一样的,区别在于java中每一个脚本会对应生成一个类文件XX.class存放在bin目录下,对应到的是scr下的java文件

1.2 技术栈
  • 开发环境:Java 17 + Eclipse(其他java编译器都可以)
  • 核心技术:面向对象编程、文件序列化、异常处理
  • 设计模式:策略模式(通过AccountOperations接口)

2、核心功能说明

2.1 账户管理

2.2 异常处理体系
public class BankException extends Exception {
     
       // 自定义异常类
    public BankException(String message) {
     
     
        super(message);
    }
}

// 使用示例:
try {
     
     
    account.withdraw(amount);
} catch (BankException e) {
     
     
    System.out.println(e.getMessage());  // 输出"余额不足"等提示
}

3、设计理念解析

3.1 面向对象设计
classDiagram
    Account <|-- CheckingAccount
    Account <|-- CreditAccount
    Account : +String accountNumber
    Account : +double balance
    Account : +deposit(double)
    Account : +withdraw(double)
    
    class CheckingAccount {
     
     
        +double checkingBalance
    }
    
    class CreditAccount {
     
     
        +double creditLimit
    }

3.2 关键设计点
  1. 抽象与继承
    1. Account抽象类实现AccountOperations接口
    2. CheckingAccountCreditAccount继承父类并重写核心方法
  2. 数据持久化
// 序列化保存
ObjectOutputStream oos = new ObjectOutputStream(
    new FileOutputStream("accounts.dat"));
oos.writeObject(accounts);

// 反序列化加载
ObjectInputStream ois = new ObjectInputStream(
    new FileInputStream("accounts.dat"));
accounts = (List<Account>) ois.readObject();

      3.模块化设计

module Bank_Management_system {
     
       // 模块化封装
    requires java.base;
    requires java.desktop;
}

4、使用指南

4.1 运行流程
  1. 启动程序:运行Main.java
  2. 主菜单操作:

  1. 创建账户示例:
// 储蓄账户
new CheckingAccount("C1001", 5000.0);

// 信用账户
new CreditAccount("CR2001", 10000.0, 50000.0);

4.2 注意事项
  1. 账户编号唯一性:系统未做重复校验,需用户自行保证
  2. 数据安全:accounts.dat文件建议定期备份
  3. 异常处理:取款操作必须进行try-catch处理

5、扩展建议

5.1增加功能
    1. 账户转账操作
    2. 交易流水记录
    3. 利息计算功能
5.2优化方向
    1. 使用数据库替代文件存储
    2. 增加图形界面(GUI)
    3. 实现账户编号自动生成

本项目通过约500行代码实现了银行核心业务逻辑,展示了以下软件工程实践:

  • 分层架构设计(模型/工具/异常分层)
  • 高内聚低耦合原则
  • 防御式编程思想
  • 数据持久化解决方案

6、主要的功能模块代码说明

Bank_Management_system\bin\com\bank 下主要的功能模块代码说明

6.1exception

--BankException.java

BankException 是一个自定义异常类,继承自 Java 的 Exception,用于在银行系统中封装特定的错误信息(如余额不足、信用额度不足等),并通过构造函数传递错误描述,使异常处理更加清晰和模块化。

package com.bank.exception;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;

public class BankException extends Exception {
     
     
    public BankException(String message) {
     
     
        super(message);
    }
}

6.2main

--Main.java

Main 类是银行账户管理系统的入口,通过控制台菜单提供账户创建、存款、取款、余额查询等功能,使用 AccountData 类实现账户数据的加载和保存,并通过 Scanner 与用户交互,确保账户操作的完整性和数据的持久化。

package com.bank.main;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;

public class Main {
     
     
    private static List<Account> accounts = new ArrayList<>();

    public static void main(String[] args) {
     
     
        Scanner scanner = new Scanner(System.in);
        int choice = -1;
        try {
     
     
            accounts = AccountData.loadAccounts(); // 从文件中读取账号列表
        } catch (Exception e) {
     
     
            System.out.println("未发现账户,请创建账户!");
        }
        while (choice != 0) {
     
     
            System.out.println("\n欢迎使用银行账户管理系统!");
            System.out.println("1. 创建账户");
            System.out.println("2. 存钱操作");
            System.out.println("3. 取钱操作");
            System.out.println("4. 显示余额");
            System.out.println("0. 退出");
            System.out.print("请选择你要进行的操作:");
            choice = scanner.nextInt();

            switch (choice) {
     
     
                case 1:
                    createAccount(scanner);
                    break;
                case 2:
                    processAccount(scanner, true);
                    break;
                case 3:
                    processAccount(scanner, false);
                    break;
                case 4:
                    showBalance(scanner);
                    break;
                case 0:
                    System.out.println("系统退出...");
                    break;
                default:
                    System.out.println("无效的选择!");
            }
        }
        scanner.close();
        try {
     
     
            AccountData.saveAccounts(accounts); // 把当前账号列表存储到文件中
        } catch (IOException e) {
     
     
            System.out.println("账户存储失败:" + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void createAccount(Scanner scanner) {
     
     
        System.out.print("请输入账户类型(1: 储蓄账户,2: 信用卡账户):");
        int accountType = scanner.nextInt();
        scanner.nextLine(); // Consume the newline
        System.out.print("请输入账户编号:");
        String accountNumber = scanner.nextLine();
        if (accountType == 1) {
     
     
            System.out.print("请输入初始余额:");
            double initialBalance = scanner.nextDouble();
            Account account = new CheckingAccount(accountNumber, initialBalance);
            accounts.add(account);
        } else if (accountType == 2) {
     
     
            System.out.print("请输入初始余额:");
            double initialBalance = scanner.nextDouble();
            System.out.print("请输入信用额度:");
            double creditLimit = scanner.nextDouble();
            Account account = new CreditAccount(accountNumber, initialBalance, creditLimit);
            accounts.add(account);
        } else {
     
     
            System.out.println("无效的账户类型!");
        }
    }

    private static void processAccount(Scanner scanner, boolean isDeposit) {
     
     
        System.out.print("请输入账户编号:");
        String accountNumber = scanner.nextLine();
        Account account = getAccount(accountNumber);
        if (account == null) {
     
     
            System.out.println("账户不存在!");
            return;
        }
        if (isDeposit) {
     
     
            System.out.print("请输入存款金额:");
            double amount = scanner.nextDouble();
            account.deposit(amount);
        } else {
     
     
            System.out.print("请输入取款金额:");
            double amount = scanner.nextDouble();
            try {
     
     
                account.withdraw(amount);
            } catch (BankException e) {
     
     
                System.out.println(e.getMessage());
            }
        }
    }

    private static void showBalance(Scanner scanner) {
     
     
        System.out.print("请输入账户编号:");
        String accountNumber = scanner.nextLine();
        Account account = getAccount(accountNumber);
        if (account == null) {
     
     
            System.out.println("账户不存在!");
            return;
        }
        System.out.println("账户余额:" + account.getBalance());
    }

    private static Account getAccount(String accountNumber) {
     
     
        for (Account account : accounts) {
     
     
            if (account.getAccountNumber().equals(accountNumber)) {
     
     
                return account;
            }
        }
        return null;
    }
}

6.3model

--Account.java

Account 是一个抽象类,实现了 AccountOperations 接口并支持序列化,用于定义银行账户的基本结构(如账户号、余额)和核心操作(存款、取款、查询余额),其中取款操作会检查余额并抛出 BankException 异常,确保账户操作的逻辑完整性和安全性。

package com.bank.model;

import java.io.Serializable;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;

public abstract class Account implements AccountOperations, Serializable {
     
     
    protected String accountNumber;
    protected double balance;

    public Account(String accountNumber) {
     
     
        this.accountNumber = accountNumber;
    }

    @Override
    public void deposit(double amount) {
     
     
        balance += amount;
    }

    @Override
    public void withdraw(double amount) throws BankException {
     
     
        if (balance < amount) {
     
     
            throw new BankException("余额不足");
        }
        balance -= amount;
    }

    @Override
    public double getBalance() {
     
     
        return balance;
    }
    
    public String getAccountNumber() {
     
     
        return accountNumber;
    }
}

--AccountOperations.java

AccountOperations 是一个接口,定义了银行账户的核心操作,包括存款 (deposit)、取款 (withdraw) 和查询余额 (getBalance),其中取款操作可能抛出 BankException 异常,确保账户操作的规范性和一致性。

package com.bank.model;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;

public interface AccountOperations {
     
     
    void deposit(double amount);
    void withdraw(double amount) throws BankException;
    double getBalance();
}

--CheckingAccount.java

CheckingAccount 是 Account 的子类,专门用于实现储蓄账户的逻辑,重写了存款 (deposit)、取款 (withdraw) 和查询余额 (getBalance) 方法,确保取款时检查存款余额并抛出 BankException 异常,同时通过调用父类方法保持账户余额的一致性。

package com.bank.model;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;


public class CheckingAccount extends Account {
     
     
    // 存款余额
    private double checkingBalance;

    public CheckingAccount(String accountNumber, double initialBalance) {
     
     
        super(accountNumber); // 调用父类构造函数,设置账户号码
        this.checkingBalance = initialBalance;
    }

    @Override
    public void deposit(double amount) {
     
     
        checkingBalance += amount;
        super.deposit(amount); // 调用父类的deposit方法,更新balance属性
    }

    @Override
    public void withdraw(double amount) throws BankException {
     
     
        if (amount > checkingBalance) {
     
     
            throw new BankException("存款余额不足");
        }
        checkingBalance -= amount;
        super.withdraw(amount); // 调用父类的withdraw方法,更新balance属性
    }

    @Override
    public double getBalance() {
     
     
        return checkingBalance; // 返回存款余额
    }
}

--CreditAccount.java

CreditAccount 是 Account 的子类,专门用于实现信用账户的逻辑,支持信用额度 (creditLimit) 的管理,重写了存款 (deposit)、取款 (withdraw) 和查询余额 (getBalance) 方法,确保取款时检查信用额度并抛出 BankException 异常,同时通过调用父类方法保持账户余额的一致性。

package com.bank.model;

import com.bank.model.AccountOperations;
import com.bank.model.Account;
import com.bank.model.CreditAccount;
import com.bank.model.CheckingAccount;

import com.bank.utils.AccountData;

import com.bank.exception.BankException;

public class CreditAccount extends Account {
     
     
    // 信用额度
    private double creditLimit;

    public CreditAccount(String accountNumber, double initialBalance, double creditLimit) {
     
     
        super(accountNumber); // 调用父类构造函数,设置账户号码
        this.creditLimit = creditLimit;
        // 由于信用账户的初始余额可以是负数,我们直接在父类中设置
        super.deposit(initialBalance); // 调用父类的deposit方法,设置初始余额
    }

    @Override
    public void deposit(double amount) {
     
     
        creditLimit += amount;
        super.deposit(amount); // 调用父类的deposit方法,更新balance属性
    }

    @Override
    public void withdraw(double amount) throws BankException {
     
     
        if (amount > creditLimit) {
     
     
            throw new BankException("信用额度不足");
        }
        creditLimit -= amount;
        super.withdraw(amount); // 调用父类的withdraw方法,更新balance属性
    }

    @Override
    public double getBalance() {
     
     
        return super.getBalance(); // 返回父类的balance属性
    }
}

6.4utils

--AccountData.java

AccountData 是一个工具类,负责银行账户数据的持久化操作,通过序列化将账户列表 (List<Account>) 保存到文件 accounts.dat 中,并通过反序列化从文件中加载账户数据,确保账户信息在程序关闭后仍能保留。

package com.bank.utils;

import com.bank.model.Account;
import com.bank.model.CheckingAccount;
import com.bank.model.CreditAccount;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class AccountData {
     
     
    private static final String ACCOUNTS_FILE = "accounts.dat";

    public static List<Account> loadAccounts() throws IOException, ClassNotFoundException {
     
     
        List<Account> accounts = new ArrayList<>();
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(ACCOUNTS_FILE))) {
     
     
            accounts = (List<Account>) ois.readObject();
        }
        return accounts;
    }

    public static void saveAccounts(List<Account> accounts) throws IOException {
     
     
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(ACCOUNTS_FILE))) {
     
     
            oos.writeObject(accounts);
        }
    }
}

7、项目反思

这样比较简易的项目,和实际的开发项目肯定是还差很多,就这个项目来看,里面的设计思路和框架对设计大的项目有用吗

有用,但需要扩展。

这个简易项目的设计思路对大型项目有帮助,但实际开发需要在此基础上大幅升级。核心价值体现在以下几个方面:

7.1基础设计思路是通用的
  • 分层结构model(数据模型)、utils(工具类)、exception(异常处理)的分包方式,是大型项目模块化的雏形。
  • 抽象与继承:用Account抽象类统一管理账户,通过子类实现差异化逻辑,这种面向对象的设计是复杂系统的基础。
  • 异常处理机制:自定义BankException的实践,直接对应企业级开发中的错误处理规范。

但问题也很明显

  • 文件存储(accounts.dat)无法支撑高并发和高数据量,实际项目需要用数据库。
  • 没有日志、单元测试、接口文档等工程化内容。
  • 业务逻辑过于简单(如没有交易流水、权限控制)。

7.2框架层面:这是“玩具级”,但能训练核心思维
  • 优势
    • 你实践了分层设计(数据存储、业务逻辑、异常分离),这是微服务架构的基础。
    • 通过接口(AccountOperations)定义行为,符合依赖倒置原则,后续可以轻松扩展新账户类型。
    • 数据持久化的实现(序列化)帮你理解了状态保存的核心问题。
  • 局限
    • 没有引入任何框架(如Spring),实际项目需要依赖注入、AOP等能力。
    • 模块化(module-info.java)仅停留在语法层面,未体现真正的模块解耦。

7.3结论:这是合格的“起点”
  • 对学习有用:如果你能清晰解释这个项目中为什么用抽象类而不用接口、为什么要序列化、异常为什么要自定义,说明你已经掌握了基础设计思维,也可以熟悉java的代码环境。
  • 对实际项目价值有限:就像学会加减法不等于会解微积分,但加减法是必要基础。要应对复杂系统,还需要学习:
    • 数据库(MySQL/MongoDB)
    • 框架(Spring Boot)
    • 设计模式(工厂、策略、观察者等)
    • 分布式概念(缓存、消息队列)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习系列75:sql大模型工具vanna

1. 概述 vanna是一个可以将自然语言转为sql的工具。简单的demo如下&#xff1a; !pip install vanna import vanna from vanna.remote import VannaDefault vn VannaDefault(modelchinook, api_keyvanna.get_api_key(my-emailexample.com)) vn.connect_to_sqlite(https://va…

C# 网络协议第三方库Protobuf的使用

为什么要使用二进制数据 通常我们写一个简单的网络通讯软件可能使用的最多的是字符串类型&#xff0c;比较简单&#xff0c;例如发送格式为(head)19|Msg:Heart|100,x,y,z…&#xff0c;在接收端会解析收到的socket数据。 这样通常是完全可行的&#xff0c;但是随着数据量变大&…

网络安全 | 什么是正向代理和反向代理?

关注&#xff1a;CodingTechWork 引言 在现代网络架构中&#xff0c;代理服务器扮演着重要的角色。它们在客户端和服务器之间充当中介&#xff0c;帮助管理、保护和优化数据流。根据代理的工作方向和用途&#xff0c;代理服务器可分为正向代理和反向代理。本文将深入探讨这两种…

Python 预训练:打通视觉与大语言模型应用壁垒——Python预训练视觉和大语言模型

大语言模型是一种由包含数百亿甚至更多参数的深度神经网络构建的语言模型&#xff0c;通常使用自监督学习方法通过大量无标签文本进行训练&#xff0c;是深度学习之后的又一大人工智能技术革命。 大语言模型的发展主要经历了基础模型阶段(2018 年到2021年)、能力探索阶段(2019年…

AIGC视频生成模型:Meta的Emu Video模型

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Meta的视频生成模型Emu Video&#xff0c;作为Meta发布的第二款视频生成模型&#xff0c;在视频生成领域发挥关键作用。 &#x1f33a;优质专栏回顾&am…

定位,用最通俗易懂的方法2.1:CRLB实例

二郎就不设置什么VIP可见啥的了&#xff0c;这样大家都能看到。 如果觉得受益&#xff0c;可以给予一些打赏&#xff0c;也算对原创的一些鼓励&#xff0c;谢谢。 钱的用途&#xff1a;1&#xff09;布施给他人&#xff1b;2&#xff09;二郎会有更多空闲时间写教程 起因&…

python学习笔记3-字符串常用的方法

一、判断&#xff08;9个&#xff09;&#xff1a; 二、查找和替换&#xff08;8个&#xff09; 三、⼤⼩写转换&#xff08;5个&#xff09; 四、⽂本对⻬&#xff08;3个&#xff09; 五、去除空⽩字符&#xff08;3个&#xff09; 六、拆分和连接 &#xff08;6个&#xff0…

【FreeRTOS 教程 一】任务结构体及其基础创建使用

目录 一、任务与协程的区别&#xff1a; &#xff08;1&#xff09;任务的特点&#xff1a; &#xff08;2&#xff09;协程的特点&#xff1a; &#xff08;3&#xff09;总结&#xff1a; 二、任务概述 &#xff1a; &#xff08;1&#xff09;任务状态&#xff1a; &…

node.js 07.npm下包慢的问题与nrm的使用

一.npm下包慢 因为npm i 默认从npm官网服务器进行下包,但是npm官网服务器是海外服务器所以响应很慢. 于是我们通过npm下包的时候通常用淘宝镜像进行下包,下面是切换到淘宝镜像地址下包的操作. 二.nrm的使用 nrm是一个管理切换npm下包地址的工具,可以快速切换下包的地址. 安…

2025发文新方向:AI+量化 人工智能与金融完美融合!

2025深度学习发论文&模型涨点之——AI量化 人工智能的融入&#xff0c;使量化交易实现了质的突破。借助机器学习、深度学习等先进技术&#xff0c;人工智能可高效处理并剖析海量市场数据&#xff0c;挖掘出数据背后错综复杂的模式与趋势&#xff0c;从而不仅提升了数据分析…

【16届蓝桥杯寒假刷题营】第1期DAY5

5.依依的询问最小值 - 蓝桥云课 问题描述 依依有个长度为 n 的序列 a&#xff0c;下标从 1 开始。 她有 m 次查询操作&#xff0c;每次她会查询下标区间在 [li​,ri​] 的 a 中元素和。她想知道你可以重新排序序列 a&#xff0c;使得这 m 次查询的总和最小。 求你求出 m 次…

25/1/15 嵌入式笔记 初学STM32F108

GPIO初始化函数 GPIO_Ini&#xff1a;初始化GPIO引脚的模式&#xff0c;速度和引脚号 GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA的引脚0 GPIO输出控制函数 GPIO_SetBits&#xff1a;将指定的GPIO引脚设置为高电平 GPIO_SetBits(GPIOA, GPIO_Pin_0); // 将GPIO…

C语言--数据在内存中的存储

数据在内存中的存储 主要研究整型和浮点型在内存中的存储。 1. 整数在内存中的存储 在学习操作符的时候&#xff0c;就了解过了下面的内容&#xff1a; 整数的2进制表示方法有三种&#xff0c;即原码、反码和补码。 有符号的整数&#xff0c;三种表示方法均有符号位和数值…

DRG_DIP 2.0时代医院程序结构转型与数据结构优化研究

一、引言 1.1 DRG_DIP 2.0 改革背景与意义 医保支付方式改革在医疗保障制度改革中占据着极为关键的地位&#xff0c;是推动医疗领域变革的核心力量。它犹如一把精准的手术刀&#xff0c;对医疗资源的合理分配、医疗服务质量的稳步提升以及医疗费用的有效控制起着决定性作用。…

炸场硅谷,大模型“蒸汽机”迎来“瓦特时刻”

作者 | 曾响铃 文 | 响铃说 中国大模型又在包括硅谷在内的全球AI圈炸场了。 两天前&#xff0c;幻方量化旗下AI公司深度求索&#xff08;DeepSeek&#xff09;&#xff0c;以及月之暗面相隔20分钟相继发布了自家最新版推理模型&#xff0c;分别是DeepSeek-R1以及Kimi 全新多…

【自动驾驶】4 智驾生态概述

目录 1 智驾生态概述 ▲ 关键组成部分 ▲ 概述 2 关键技术 ▲ 传感器 ▲ 感知 ▲ 数据闭环 3 未来市场 1 智驾生态概述 智能驾驶生态&#xff0c;简称智驾生态&#xff0c;是指围绕智能驾驶技术的开发、应用、服务和支持所形成的产业体系和合作网络。 涵盖了从硬件设…

Excel 技巧14 - 如何批量删除表格中的空行(★)

本文讲如何批量删除表格中的空行。 1&#xff0c;如何批量删除表格中的空行 要点就是按下F5&#xff0c;然后选择空值条件以定位所有空行&#xff0c;然后删除即可。 按下F5 点 定位条件 选 空值&#xff0c;点确认 这样就选中了空行 然后点右键&#xff0c;选 删除 选中 下方…

C语言进阶习题【1】指针和数组(4)——指针笔试题3

笔试题5&#xff1a;下面代码输出是是什么&#xff1f; int main() {int a[5][5];int(*p)[4];p a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0; }分析 代码结果 笔试题6&#xff1a;下面代码输出是是什么&#xff1…

5. 推荐算法的最基础和最直观的认识

1.性别年龄转换为统一的计量单位 所谓推荐&#xff0c;就是替别人推荐&#xff0c;比如工厂A需要招男员工&#xff0c;希望大家推荐认识的人。那么在这里&#xff0c;就有了推荐的概念&#xff0c;限定条件是男。我们知道&#xff0c;人的性别一般分为男或者女。在这里假设把男…

如何在Matplotlib中绘制多个Y轴刻度

Matplotlib是一个功能强大的Python库&#xff0c;在它的帮助下&#xff0c;我们可以绘制条形图&#xff0c;图表&#xff0c;绘图&#xff0c;比例等。在本文中&#xff0c;我们将尝试在Matplotlib中绘制多个Y轴刻度。 为什么多个Y轴刻度很重要&#xff1f; 绘制具有不同单位…