【Java】—— 图书管理系统
基于往期学习的类和对象、继承、多态、抽象类和接口来完成一个控制台版本的 “图书管理系统”
在控制台界面中实现用户与程序交互
任务目标:
1、系统中能够表示多本图书的信息
2、提供两种用户(普通用户,管理员)
3、普通用户:查看书籍列表,查找图书,借书,还书
4、管理员:查看书籍列表,查找图书,新增图书,删除图书
任务实现:
1、图书类
创建一个包 library 用来表示 图书管理系统 ,再创建 Book 类表示 一本的图书信息

在类里创建需要用到的属性(书名,作者,价格,类型,是否被借出)
package library;public class Book {private String name; //书名private String author; //作者private double price; //价格private String type; //类型private Boolean isBorrowed; //是否被借出//构造方法//当新增图书时,默认是未被借出public Book(String name, String author, double price, String type) {this.name = name;this.author = author;this.price = price;this.type = type;this.isBorrowed = false;}//提供 get/set 方法public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public String getType() {return type;}public void setType(String type) {this.type = type;}public Boolean getBorrowed() {return isBorrowed;}public void setBorrowed(Boolean borrowed) {isBorrowed = borrowed;}
}
2、图书列表类
创建一个 BookList 类用来管理多个书籍对象
package library;public class BookList {//创建数组来记录多本书的信息private Book[] books = new Book[100];private int size = 0;//当前数组中有效元素的个数//构造方法public BookList(){//默认添加几本书,方便后续测试books[0] = new Book("西游记","吴承恩",100.0,"古典名著");books[1] = new Book("高等数学","高斯",90.0,"自然科学");books[2] = new Book("福尔摩斯探案集","阿瑟·柯南·道尔",110,"悬疑推理小说");size = 3;}//提供 get/set 方法public int getSize() {return size;}public void setSize(int size) {this.size = size;}public Book getBook(int index){return books[index];}public void setBooks(int index,Book book){books[index] = book;}
}
3、用户类
因为 普通用户 和 管理员 是从 用户 中根据不同的权限分离出来的,这里就涉及到了 继承 的知识,让 子类 继承 父类 来减少代码量
package library.User;import library.IOperation;//用户父类,派生出子类管理员和普通用户
public abstract class User {//这里用 protected 修饰 name,可以让子类直接获取到,不用 get/set 方法protected String name;//当前这个类能够进行哪些操作,就往这个数组中添加对应的对象protected IOperation[] operations;//构造方法public User(String name) {this.name = name;}//管理员和普通用户的权限不一样,菜单面板也有所不同,//但是在父类中没有办法确定使用哪个菜单,所以可以写成抽象类,让子类去进行重写//通过返回用户输入的序号来决定执行不同的操作,所以使用 int 类//写成 抽象方法 后就需要将这个父类写成 抽象类public abstract int menu();
}
父类写到这,我们就可以去创建子类
4、普通用户类(NormalUser)
import java.util.Scanner;public class NormalUser extends User{public NormalUser(String name) {super(name);}@Overridepublic int menu() {//打印普通用户的菜单System.out.println("===========================");System.out.println("欢迎您" + name + "!");System.out.println("1. 查看书籍列表");System.out.println("2. 按照名字查找图书");System.out.println("3. 借阅图书");System.out.println("4. 归还图书");System.out.println("0. 退出");System.out.println("===========================");System.out.println("请输入您的操作:");Scanner scanner = new Scanner(System.in);int choice = scanner.nextInt();return choice;}
}
5、管理员类(Admin)
import java.util.Scanner;public class NormalUser extends User{public NormalUser(String name) {super(name);}@Overridepublic int menu() {//打印普通用户的菜单System.out.println("===========================");System.out.println("欢迎您" + name + "!");System.out.println("1. 查看书籍列表");System.out.println("2. 按照名字查找图书");System.out.println("3. 借阅图书");System.out.println("4. 归还图书");System.out.println("0. 退出");System.out.println("===========================");System.out.println("请输入您的操作:");Scanner scanner = new Scanner(System.in);int choice = scanner.nextInt();return choice;}
}
写到这里 书 和 用户 的代码还没有进行交互,这就是面向对象程序设计的典型特点,先创建核心的类/对象,把 核心类/对象属性、方法 搞出来,再通过主逻辑把多个 类/对象 串起来。
6、基本操作接口
创建接口是为了保证所有的类都提供 work 方法,保证 work 的参数都是一致的,也方便之后调用
(这里不使用 接口 使用 抽象类 也是可以的,主要是因为当前没有什么实例属性需要子类来继承(前文中的用户,有 name 属性需要被继承,所以所以使用了抽象类),当两种写法都可以时,优先考虑使用接口)

通过 Operation 把 用户 和 书 关联起来
package library.operation;import library.BookList;//通过这个接口来表示用户的一种基本操作
public interface IOperation {//给出抽象方法//此处操作的 work 方法,是针对 “多本书” 来进行操作的//后续再创建操作相关的具体的类,实现这个接口,就要进一步实现这里的操作void work(BookList bookList);}
把操作单独提取成类

这些类都要实现自 IOperation 接口,并且重写其中的 work 方法
package library.operation;import library.BookList;public class AddOperation implements IOperation{@Overridepublic void work(BookList bookList) {}
}
由于当前每个操作都实现了 IOperation 接口,就只需要给这两种用户添加一个 IOperation[ ] 的数组保存能够支持的操作有什么就可以了
回到 普通用户 和 管理员 创建好数组,并在数组里写上要实现的操作
普通用户的操作
数组是 普通用户 和 管理员 都需要,所以直接在父类创建即可

public NormalUser(String name) {super(name);operations = new IOperation[]{new ExitOperation(),new ListOperation(),new FindOperation(), new BorrowOperation(), new ReturnOperation()};}
注意这里创建的是数组,元素和元素直接用 “,”隔开。
数组创建写在构造方法内,实例化一个用户,都要操作可以调用
管理员的操作
public Admin(String name) {super(name);operations = new IOperation[]{new ExitOperation(),new ListOperation(),new FindOperation(),new AddOperation(),new DelOperation()};}
7、Main 类
当我们准备好了所有对象(书、用户、操作),就可以通过一个主逻辑将所有内容串起来
7.1 创建书籍管理对象
BookList bookList = new BookList();
7.2 创建用户对象
这里的身份有两个,所以需要写一个方法,让用户自己选择一个身份
//实例化用户对象
User user = login();//选择身份方法
private static User login(){//让用户输入自己的身份Scanner scanner = new Scanner(System.in);System.out.println("请输入您的姓名:");String name = scanner.next();System.out.println("请输入你的身份:(1 普通用户,2 管理员)");int role = scanner.nextInt();if(role == 1){return new NormalUser(name);} else if (role == 2) {return new Admin(name);}else {System.out.println("输入有误");return null;}
}
7.3 构建一个主循环
用户可以不断选择要进行的操作
while(true){}
7.4 显示用户对应的菜单
while(true){//这里会触发多态,根据实际指向来决定是谁的菜单int choice = user.menu();
}
7.5 根据序号,执行对应操作
//给user 提供一个对应的 “执行” 的方法,最终都是落到对应的 IOperation 对象上
user.work(choice,bookList);//回到 User 类里创建对应方法
public void work(int choice, BookList bookList){//这个操作,是通过输入的 choise 值选择数组中对应的那个操作//这里每个操作的下标要和菜单上的序号一一对应//这里还可以添加一个判断,判断输入的数字是否合法if(choice < 0 && choice > operations.length){System.out.println("输入的选项非法");return;}operations[choice].work(bookList);
}
当主逻辑写到这里,就可以进行测试了

测试顺利就可以进入最后的 操作实现
8、IOperation 操作实现
8.1 ExitOperation
package library.operation;import library.BookList;public class ExitOperation implements IOperation{@Overridepublic void work(BookList bookList) {//只需要结束整个程序System.out.println("Goodbye!");//这里的参数是程序的退出码,不重要System.exit(0);}
}

8.2 ListOperation
package library.operation;import library.Book;
import library.BookList;public class ListOperation implements IOperation{@Overridepublic void work(BookList bookList) {System.out.println("查看书籍列表");for(int i = 0 ; i< bookList.getSize();i++){Book book = bookList.getBook(i);System.out.println("[" + i + "]" + book);}}
}
通过 for 循环对我们存储书的数组进行遍历,循环的次数来自父类的 size ,循环里分别指向图书列表每一个,最后进行打印,这里在打印时添加一个下标,方便之后进行利用下标进行删除

我们会看到打印出来的结果是一段哈希码,我们需要再写一个 toString 方法,回到 Book类中
@Override
public String toString() {return "[" + name + "," + author + "," + price + "," + type + "," + isBorrowed + "]";
}

这样就把我们的书籍列表打印出来了
8.3 AddOperation
让用户输入新的书籍,并添加到书籍列表中
package library.operation;import jdk.swing.interop.SwingInterOpUtils;
import library.Book;
import library.BookList;import java.util.Scanner;public class AddOperation implements IOperation{@Overridepublic void work(BookList bookList) {System.out.println("新增图书");Scanner scanner = new Scanner(System.in);System.out.println("请输入一个书名:");String name = scanner.next();System.out.println("请输入作者:");String author = scanner.next();System.out.println("请输入价格:");Double price = scanner.nextDouble();System.out.println("请输入类型:");String type = scanner.next();Book book = new Book(name,author,price,type);int size = bookList.getSize();bookList.setBooks(size,book);bookList.setSize(size + 1);System.out.println("新增图书完成");}
}
通过 书 的四个属性创建一本新的书,先获取 size 再通过 size 来找到 书 存放的位置,最后让 size+1 表示当前图书的有效位置


可以看到已经成功将新书存入书籍列表中了
8.4 DelOperation
在写删除之前先来了解一个小知识,当我们进行删除文件时,总是能非常快速的完成,无论文件大小,删除都是一瞬间。因为在硬盘里,当你进行删除时,硬盘会将你所删除的这个文件在的位置声明这里没有东西,实际上你的文件还是存在,只是之后新的数据会覆盖在这个区域上。这也是文件误删后可以通过技术手段进行找回的原因
在这写删除仍然使用这个概念,当我们删除图书时,只需要将有效图书个数-1就可以,书依然存在数组里但是不会显示出来。
这里又牵出了一个问题,有效个数-1只会让最后一本图书不显示,当删除的书不是最末尾的书呢,所以这里可以将问题转换,如果要删除其中一本,只要让这本和最末尾的书进行交换即可
package library.operation;import library.BookList;import java.util.Scanner;public class DelOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要删除的图书序号");//创建变量 index 来记录要删除的图书的序号int index = scanner.nextInt();//判断一下序号是否在范围内if(index<0 || index>=bookList.getSize()){System.out.println("序号有误");return ;}//判断删除的序号是不是最后一本if(index == bookList.getSize() -1){//如果是最后一本,就把 Size-1 bookList.setSize(bookList.getSize() -1);}else {//如果不是最后一本,就要把最后一本复制到删除的序号位置// 修改图书(要修改的下标,要修改的图书 (最后一本书的下标))bookList.setBooks(index,bookList.getBook(bookList.getSize()-1));//最后也要让 Size-1bookList.setSize(bookList.getSize() -1);}System.out.println("删除成功");}
}
删除前:

进行删除:

删除后:

原来在最后的福尔摩斯探案集就来到原来高等数学的位置,这样就算删除成功了
8.5 BorrowOperation
借阅只需要修改单个属性即可
package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class BorrowOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要借阅的图书序号");int index = scanner.nextInt();//这里将我们要借阅的图书实例化,才可以修改它的 BorrowBook book = bookList.getBook(index);//因为Borrwed属性是布尔值,所以不需要去写 == trueif(book.getBorrowed()){System.out.println("该书已被借阅");}else {//借阅成功后修改属性book.setBorrowed(true);System.out.println("借阅成功");}}
}
借阅过程:

借阅结果:

8.6 ReturnOperation
归还图书也差不多,只需要修改一些内容
package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class ReturnOperation implements IOperation{@Overridepublic void work(BookList bookList) {Scanner scanner = new Scanner(System.in);System.out.println("输入要归还的图书序号");int index = scanner.nextInt();Book book = bookList.getBook(index);if(book.getBorrowed()){book.setBorrowed(false);System.out.println("归还成功");}else {System.out.println("该书未被借阅");}}
}
8.7 FindOperation
这里写简单一些,只通过书名来查找书的序号
package library.operation;import library.Book;
import library.BookList;import java.util.Scanner;public class FindOperation implements IOperation{@Overridepublic void work(BookList bookList) {//输入姓名Scanner scanner = new Scanner(System.in);String name = scanner.next();//对所有图书进行遍历for(int i = 0;i< bookList.getSize();i++){//对图书进行实例化Book book = bookList.getBook(i);//判断字符串是否相等需要用到equalsif(book.getName().equals(name)){//相等则打印书籍信息System.out.println(book);}}System.out.println("查找结束");}
}
完
相关文章:
【Java】—— 图书管理系统
基于往期学习的类和对象、继承、多态、抽象类和接口来完成一个控制台版本的 “图书管理系统” 在控制台界面中实现用户与程序交互 任务目标: 1、系统中能够表示多本图书的信息 2、提供两种用户(普通用户,管理员) 3、普通用户…...
数据库基础入门:从零开始学习数据库的核心概念
数据库是现代软件开发的核心组成部分之一,无论是网站、手机应用还是企业管理系统,都离不开数据库的支持。本文将带你从零开始,逐步了解数据库的基本概念和常见操作。 什么是数据库? 数据库(Database)是一个…...
Y20030002 微信+Java+Jsp+Servlet+MySQL的问卷调查小程序的设计与实现 源代码 配置文档 全套资料
问卷调查微信小程序 1.摘要2. 系统开的背景和意义3. 国内外研究现状4. 系统功能5.界面展示6.源码获取 1.摘要 摘 要:本文深入研究并实现了一个基于微信小程序的问卷调查系统。微信小程序问卷调查系统借助于微信小程序的便捷性和普及性,为用户提供了一个…...
ros项目dual_arm_pick-place(urdf文件可视化查看)
前言 一直想写一些项目的讲解,今天(2024.12.05)可以说正式开始了。 dual_arm_pick-place项目,是关于两个机械臂协同传递物品。 正文 这次的话,给大家讲一下里面的urdf文件。 这篇文章主要来看一下项目中的urdf文件…...
AI-安全-B站
1 需求 百度-林道正-《大模型合规探索》火山引擎-林泽韬-《大模型安全挑战与防护实践》Chamd5-bayuncao-《基于RAG的AI代码审计框架》德国电信咨询有限公司-杨麟-《AI在SOC中的应用发展》360-李亚青-《以模制模,大模型安全的解决之道》金晴云华-富吉祥-《安全大脑在…...
【C#设计模式(19)——备忘录模式(MementoPattern)】
前言 备忘录模式:将想要备份的信息交给备忘录对象来管理。通过设置初始、备份、修改、恢复等状态展示备忘录模式的使用。 代码 //备忘录类 public class Memento {private string state;public string State { get>state;}public Memento(string state){this.st…...
第三部分:进阶概念 8.事件处理 --[JavaScript 新手村:开启编程之旅的第一步]
JavaScript 事件处理是 Web 开发中不可或缺的一部分,它允许开发者响应用户的交互行为(如点击、键盘输入等)或浏览器的行为(如页面加载完成)。通过事件处理,我们可以使网页更加动态和互动。以下是关于 JavaS…...
工具推荐-js爬取工具
现在测试方向都偏向于从js中的接口来入手找到可以进的点,关于快速扫描js文件来发现敏感接口的工具有很多,下面的jjjjs就是其一 项目地址: GitHub - ttstormxx/jjjjjjjjjjjjjs: 爬网站JS文件,自动fuzz api接口,指定api接口&#x…...
Android问题记录 - Inconsistent JVM-target compatibility detected for tasks
文章目录 前言开发环境问题描述问题分析解决方案补充内容最后 前言 前段时间升级Android Studio后修复了一堆问题,详情请看:Android问题记录 - 适配Android Studio Ladybug/Java 21/AGP 8.0(持续更新)。我以为问题已经全部解决了…...
ejb组件(rmi) webservice平台(xml)
springboot bean 在 Spring Boot 中,Bean 是 Spring 框架的核心概念之一,表示由 Spring 容器管理的对象。通过 Bean 或其他注解(如 Component、Service、Repository 等)来定义和管理这些对象。以下是关于 Spring Boot 中 Bean 的…...
【jvm】垃圾回收的重点区域
目录 1. 说明2. 堆(Heap)3. 方法区(Method Area) 1. 说明 1.JVM(Java Virtual Machine)垃圾回收的重点区域主要集中在堆(Heap)和方法区(Method Area)。2.堆是…...
PyQt信号槽实现页面的登录与跳转 #页面进一步优化
将登录框中的取消按钮使用信号和槽的机制,关闭界面。 将登录按钮使用信号和槽连接到自定义的槽函数中,在槽函数中判断ui界面上输入的账号是否为"admin",密码是否为"123456",如果账号密码匹配成功,当前界面关…...
谈谈web3
全面解析 Web3:未来互联网的革命性进程 引言:互联网进化的三部曲 互联网的发展经历了三个重要阶段,每一个阶段都深刻地改变了我们的生活方式: Web1(1990-2005):静态互联网时代,人…...
正则表达式实战例子
正则表达式实战例子 1. 验证电子邮件地址 定义一个合理的电子邮件格式,并检查给定的字符串是否符合这个模式。 import redef is_valid_email(email):# 定义电子邮件格式的正则表达式pattern r^[a-zA-Z0-9_.-][a-zA-Z0-9-]\.[a-zA-Z0-9-.]$return bool(re.match(…...
Hadoop不同版本的区别
免费springboot,vue,springcloudalibaba视频,有兴趣可以看看 <!-- springboot,springboot整合redis,整合rocketmq视频: --> https://www.bilibili.com/video/BV1nkmRYSErk/?vd_source14d27ec13a473…...
QtCreator UI界面 菜单栏无法输入中文
如下图红色所示的区域,直接输入是无法输入中文的: 解决方法:在右边的属性值里输入即可 也可以参考这位同学的解决方法:友情链接...
java switch及其新特性
switch是什么 在Java中,switch语句是一种多分支选择结构,它允许程序根据一个表达式的值从多个代码块中选择执行哪一个。switch语句通常比多个if-else语句更清晰、更易读。 Java switch语句的基本语法: switch (expression) {case value1:/…...
E卷-货币单位换算(100分)
货币单位换算 问题描述 在一个多国货币记账本中,记录了若干条不同货币的金额。现在需要将这些金额全部转换成人民币分(fen),并进行汇总。每条记录可能包含单独的元、单独的分,或者元与分的组合。转换时,需要考虑不同货币之间的汇率关系。 要求将这些货币全部换算成人民…...
什么是MMD Maximum Mean Discrepancy 最大均值差异?
9多次在迁移学习看到了,居然还是Bernhard Schlkopf大佬的论文,仔细看看。 一.什么是MMD? 1. MMD要做什么? 判断两个样本(族)是不是来自于同一分布 2.怎么做?(直观上)…...
沐风老师3DMAX摄相机阵列插件使用方法
3DMAX摄相机阵列插件,从网格对象或样条线的顶点法线快速创建摄相机阵列。该插件从网格的顶点或样条线的节点获取每个摄影机的位置和方向。 3DMAX摄相机阵列插件支持目前3dMax主流的物理相机、标准相机、VRay物理相机。 【版本要求】 3dMax 2015及更高版本 【安装方…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
