【java】图书管理系统

  • 完整代码链接:https://gitee.com/zeng-xuehui/Java_repository/tree/master/test_11_27_1/src
  • 我们在写这个系统时,首先需要搭建框架,再实现业务逻辑;
  • 图书管理系统是用户通过各种功能图书进行操作的一个系统;
  • 我们需要通过三方面进行编写代码:1、用户  2、功能 3、图书,所以代码大的分为了这三部分;

1、代码主要就分为三大模块和一个Main类来测试图书管理系统;


2、 book包中的Book类和BookList类

Book类:是用来描述书这个对象的;

BookList类:用来描述书架上的书;

Book类代码:

package book;

public class Book {
    // book的属性
    private String name; // 名字
    private String author; // 作者
    private int price; // 价格
    private String type; // 类型
    private Boolean isBorrow = false; // 是否借阅->初始值false
    // 如果这里不初始化,后面有些地方使用到isBorrow这个属性就会报错;

    // 书的初始化
    public Book() {

    }
    public Book(String name, String author, String type, int price) {
        this.name = name;
        this.author = author;
        this.type = type;
        this.price = price;
    }

    // 方法



    public void setBorrow(Boolean isBorrow) {
        this.isBorrow = isBorrow;
    }
    public String getName() {
        return name;
    }

    public String getAuthor() {
        return author;
    }

    public int getPrice() {
        return price;
    }

    public String getType() {
        return type;
    }

    public Boolean getBorrow() {
        return isBorrow;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setType(String type) {
        this.type = type;
    }

    public void setPrice(int price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", type='" + type + '\'' +
                ((isBorrow == true)? " 已借阅":" 未借阅") +
                '}';
    }
}

BookList类代码:

package book;

/**
 * 难点:数组的初始化、数组应该如何使用
 * 1、this.books = new Book[10]; // 将书架初始化为10,可以存放10本书
 *
 */

public class BookList {
    // 存放书本
    private Book[] books; // 这是书架,存放书本
    private int useSize; // 存放数量
    // 初始化
    public BookList() {
        this.books = new Book[10]; // 将书架初始化为10,可以存放10本书
        // 书架上有两本书,所以可以通过实例代码块实现,或者构造代码块实现
        this.books[0] = new Book("java","高斯林","编程",32);
        this.books[1] = new Book("C语言","xxxx","编程",45);
        this.useSize = 2; // 书架上有两本书
    }

    public Book getBooks(int pos) {
        return this.books[pos];
        // 这里返回的是一本书,所以返回值是Book
    }
    public void setBook(Book book, int pos) {
        // 书架上新增一本书,新增到哪个位置
        this.books[pos] = book;
    }

    public int getUseSize() {
        return useSize;
    }
    public void setUseSize(int useSize) {
        this.useSize = useSize;
    }
}

 

3、 user包中的User类、Administractor类、OrdinaryUser类

User类:用来描述用户这个对象的;

Administractor类:主要写的是管理员用户的特有方法和属性;

OrdinaryUser类:主要写的是普通用户的特有方法和属性;

在这里的有一个难点:我最初写的时候不理解功能数组的初始化

User类代码:

package user;

import book.BookList;
import function.Function;

/**
 *  难点:在用户中定义功能数组
 *  1、protected Function[] functions; // 数组并没有初始化,没有为数组分配空间
 */

public abstract class User {
    protected Function[] functions; // 数组并没有初始化,没有为数组分配空间
    //用户属性
    private String name; // 这是用户的姓名

    public User(String name) {
        this.name = name;
    }
    // 方法
    public abstract int menu();
    // 功能实现的方法
    public void function(int choose, BookList bookList) {
        // this.functions[] -> 这是一个功能对象
        // this.functions[choose].work() -> 调用对象中的方法
        // this.functions[choose].work(bookList);
        // 接口不能new,但是接口可以引用对象,这里接口是应用的对象
        Function function = this.functions[choose]; // 这是功能对象
        function.work(bookList);
    }
}

 Administractor类代码:

package user;

import function.*;

import java.util.Scanner;

/**
 * 难点:功能数组初始化
 * // this既可以调用子类的成员,也可以调用父类的成员
 *         this.functions = new Function[]{
 *                 new ExitSystem(),
 *                 new AddFunction(),
 *                 new ReturnFunction(),
 *                 new DeleteFunction(),
 *                 new ShowFunction()
 *         };
 * 难点:选择功能之后为什么没有实现对应的功能
 */

public class Administrator extends User{
    public Administrator(String name) {
        super(name);
        // this既可以调用子类的成员,也可以调用父类的成员
        this.functions = new Function[]{
                new ExitSystem(),
                new AddFunction(),
                new ReviseFunction(),
                new DeleteFunction(),
                new ShowFunction()
        };
    }
    @Override
    public int menu() {
        System.out.println(".........管理员.........");
        System.out.println("0、退出系统");
        System.out.println("1、增加图书");
        System.out.println("2、修改图书");
        System.out.println("3、删除图书");
        System.out.println("4、显示图书");
        System.out.println(".......................");
        System.out.print("请选择功能:");
        Scanner scanner = new Scanner(System.in);
        int choose = scanner.nextInt();
        return choose;
    }
}

 OrdinaryUser类代码:

package user;

import function.*;

import java.util.Scanner;

/**
 * 难点:数组的初始化
 * // this既可以调用子类的成员,也可以调用父类的成员
 *         this.functions = new Function[]{
 *                 new ExitSystem(),
 *                 new BorrowFunction(),
 *                 new ReturnFunction(),
 *                 new ShowFunction()
 *         };
 * 难点:选择功能之后为什么没有实现对应的功能
 */

public class OrdinaryUser extends User{

    public OrdinaryUser(String name) {
        super(name);
        // this既可以调用子类的成员,也可以调用父类的成员
        this.functions = new Function[]{
                new ExitSystem(),
                new BorrowFunction(),
                new ReturnFunction(),
                new ShowFunction(),
                new FindFunction()
        };
    }

    // 方法
    @Override
    public int menu() {
        System.out.println("........普通用户........");
        System.out.println("0、退出系统");
        System.out.println("1、借阅图书");
        System.out.println("2、归还图书");
        System.out.println("3、显示图书");
        System.out.println("4、查找图书");
        System.out.println(".......................");
        System.out.print("请选择功能:");
        Scanner scanner = new Scanner(System.in);
        int choose = scanner.nextInt();
        return choose;
        // 选择之后为什么没有实现功能呢?
    }
}

 

 4、function包中的各种操作类和一个Function接口

操作类:管理员的操作类、普通用户的操作类;

Function接口:通过操作类实现这个Function接口,目的就是使操作分离;

 Function接口代码:

package function;

import book.BookList;

public interface Function {
    // 这些功能都是对书架上的书进行操作
    // 所以在操作时需要将书架传过来
    void work(BookList bookList);
}

 操作类代码:

新增图书代码:

package function;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class AddFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("增加图书");
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入新增图书书名:");
        String name = scanner.nextLine();
        System.out.print("请输入新增图书作者:");
        String author = scanner.nextLine();
        System.out.print("请输入新增图书类型:");
        String type = scanner.nextLine();
        System.out.print("请输入新增图书价格:");
        int price = scanner.nextInt();
        // 新增了书本,所以我们需要构造出一个书的对象
        Book book = new Book(name, author, type, price);

        // 新增图书所放的位置
        // 可以放在数组的开头,也可以放在数组的中间,还可以放在数组的末尾
        // 但是所放的位置,不允许当前位置之前为空!!!前一个位置必须有数据
        // 但是我们在放这本书之前需要判断书架中是否存在这本书
        for (int i = 0; i < bookList.getUseSize(); i++) {
            Book systemBook = bookList.getBooks(i);
            if(systemBook.getName().equals(name)) {
                System.out.println("书架中已存在此书,新增失败!");
                return ;
            }
        }
        // 走到这里说明书架上没有这本书,新增成功
        // 但是我们应该怎么在书架中新增呢?
        // 将书放到数组中的某个下标就新增成功
        bookList.setBook(book, bookList.getUseSize());
        bookList.setUseSize(bookList.getUseSize() + 1);
        System.out.println("新增成功!");
    }
}

 借阅图书代码:

package function;

import book.Book;
import book.BookList;

import java.util.Scanner;

/**
 * 发现一个问题:借阅图书和归还图书都没有实际的操作,并没有使书架上的书减少,仅仅只是显示借阅和归还
 * 借阅、归还图书操作并没有改变书架上的书
 */

public class BorrowFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("借阅图书");
        System.out.print("请输入借阅图书的书名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        // 再进行比较,存在这本书、不存在这本书;
        int i = 0;
        for (i = 0; i < bookList.getUseSize(); i++) {
            if(bookList.getBooks(i).getName().equals(name)) {
                // 进入这里面说明书架中有这本书
                bookList.getBooks(i).setBorrow(true);
                System.out.println("借阅成功!");
                return; // 这里直接return,下面就不需要再进行判断
            }
        }
        System.out.println("图书中没有这本书:" + name);
    }
}

 删除图书代码:

package function;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class DeleteFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("删除图书");
        int index = -1; // 用来记录要删除图书的下标
        System.out.print("请输入要删除图书书名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        int i = 0;
        for (i = 0; i < bookList.getUseSize(); i++) {
            // 先找到对应下标的书
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)) {
                // 走到这儿说明已经找到了这本图书
                // 当找到这本书就跳出循环
                // 将找到书的下标给到index
                index = i;
                break;
            }
        }
        // 走到这里说明在书架中没有找到这本书
        if(i >= bookList.getUseSize()) {
            System.out.println("书架中没有要删除的这本书!");
            return ; // 结束当前这个方法
        }

        // 如何删除一本书,先在已经有了这本书的下标index
        // 这里还需要考虑的是j小于多少,如果不减1的话会出现数组越界
        for (int j = index; j < bookList.getUseSize()-1; j++) {
            // 写到这里,怎么调用数组呀?
            // 现在通过getBooks这个方法拿到了j+1位置处的下标
            Book book = bookList.getBooks(j+1);
            // 现在这个setBook方法,将book这本书放到j位置
            bookList.setBook(book,j);
        }

        // 还需要将最后没有使用的对象置为空
        bookList.setBook(null, bookList.getUseSize()-1);
        bookList.setUseSize(bookList.getUseSize()-1);
    }
}

 退出系统代码:

package function;

import book.BookList;

public class ExitSystem implements Function{

    @Override
    public void work(BookList bookList) {
        System.out.println("退出系统");
        System.exit(0);
        // 应该要对bookList手动回收
    }
}

查找图书代码:

package function;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class FindFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("查找图书");
        // 查找图书需要输入查找内容
        System.out.print("请输入要查找的图书书名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        // 输入的数需要与书架上的书进行对比
        // 难点:怎么和书架上的书进行比较
        // 现在就是要遍历书架上的书
        // 每遍历一次就要拿到一本书
        // 拿到一本书后返回它的下标进行比较
        for (int i = 0; i < bookList.getUseSize(); i++) {
            // Book book = bookList[i];
            // 这样写是错的,bookList是一个类,类中的Book对象才是一个数组
            // 由于Book数组对象是一个私有的对象,所以需要提供一个方法来获取到i下标的对象
            Book book = bookList.getBooks(i);
            // 上面是查找的书名,所以比较的也是书名,需要获取到当前下标的书名
            if(book.getName().equals(name)) {
                System.out.print("存在这本书,信息如下:");
                // 还有这里为什么直接就调用了Book类中的toString方法呢?
                System.out.println(book);
                return ; // 当我们找到了就要结束这个方法
            }
        }
        System.out.println("没有你要找的书:" + name);
    }
}

 归还图书代码:

package function;

import book.BookList;

import java.util.Scanner;

public class ReturnFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("归还图书");
        System.out.print("请输入要归还图书的书名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        // 再进行比较,存在这本书、不存在这本书;
        int i = 0;
        for (i = 0; i < bookList.getUseSize(); i++) {
            if(bookList.getBooks(i).getName().equals(name)) {
                // 进入这里面说明书架中有这本书
                bookList.getBooks(i).setBorrow(false);
                System.out.println("归还成功!");
                return; // 这里直接return,下面就不需要再进行判断
            }
        }
        System.out.println("图书中没有要归还的这本书:" + name);
    }
}

 修改图书代码:

package function;

import book.Book;
import book.BookList;

import java.util.Scanner;

public class ReviseFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("修改图书");
        // 请输入要修改的图书
        System.out.print("请输入要修改的图书:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        // 判断书架上是否有这本书
        for (int i = 0; i < bookList.getUseSize(); i++) {
            Book book = bookList.getBooks(i);
            if(book.getName().equals(name)) {
                // 走到这里说明书架上有这本书
                System.out.print("请输入要修改的图书的书名:");
                String bookName = scanner.nextLine();
                book.setName(bookName);
                System.out.print("请输入要修改的图书的作者:");
                String bookAuthor = scanner.nextLine();
                book.setAuthor(bookAuthor);
                System.out.print("请输入要修改的图书的类型:");
                String bookType = scanner.nextLine();
                book.setType(bookType);
                System.out.print("请输入要修改的图书的价格:");
                int bookPrice = scanner.nextInt();
                book.setPrice(bookPrice);
                System.out.println("修改成功!");
                return;
            }
        }
        System.out.println("书架上没有要删除的这本书:" + name);
    }
}

 显示图书代码:

package function;

import book.Book;
import book.BookList;

public class ShowFunction implements Function{
    @Override
    public void work(BookList bookList) {
        System.out.println("显示图书");
        // 显示图书就是拿到一本书的下标就打印一本书
        for (int i = 0; i < bookList.getUseSize(); i++) {
            // 先拿到这本书的下标
            Book book = bookList.getBooks(i);
            System.out.println(book);
        }
    }
}

 

5、Main类测试图书管理系统

Main类代码:

import book.Book;
import book.BookList;
import function.Function;
import user.Administrator;
import user.OrdinaryUser;
import user.User;

import java.util.Scanner;

/**
 *  * 1、找对象、创建对象、实现对象
 *  * 2、最容易想到的两个对象->书、人
 *  * 3、实现书这个对象,但是书不止一本,所以需要书架
 *  * 4、书架是用来存放书的,其中涉及的数组是难点(!)
 *  * 5、操作人员->普通用户、管理员用户
 *  * 6、不用的用户所提供的操作不相同,如何实现各自操作的分离
 *  * 7、每一个操作都写成一个类当中,每一个类都是对书进行操作,将这个对书的操作写成一个接口,每个类再去实现接口中的方法
 *  * 8、实现一个接口数组,一个是普通用户的操作接口数组,一个书管理员用户的操作接口数组,这样就将各自的操作分离了出来,目的就是为了类型统一
 *  * 9、用户是一个类,用户的基本信息应该包含;但是用户分为->普通用户、管理员用户;这两个类是用户类的子类;这三个类应该如何协同操作呢?
 *  * 10、我们需要一个登录页面进行操作
 */
public class Main {
    public static User login() {
        System.out.print("请输入你的姓名:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        System.out.println("请选择你的身份:1、管理员用户 2、普通用户");
        int choose = scanner.nextInt();
        if(choose == 1) {
            return new Administrator(name);
        }else {
            return new OrdinaryUser(name);
        }
    }
    public static void main(String[] args) {
        BookList bookList = new BookList();
        // 登录页面
        User user = login();
        while(true) {
            // 循环操作
            int choose = user.menu(); // 返回了一个功能选择,所以需要接收
            // 难点:那么需要怎样调用这些功能呢?
            user.function(choose,bookList);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Google play开发者账号付款资料暂停的原因及解决方案

相信大多数Google play开发者都收到过这封邮件 邮件内容的大致意思是“由于可疑的活动&#xff0c;我们暂停了你的付款资料。” “要恢复您的帐户&#xff0c;请转到您的帐户并执行所要求的操作。” 这是触发了谷歌的付款风控机制&#xff0c;根据开发者们的反馈&#xff0c;账…

Making Reconstruction-based Method Great Again for Video Anomaly Detection

Making Reconstruction-based Method Great Again for Video Anomaly Detection 文章信息&#xff1a; 发表于ICDM 2022&#xff08;CCF B会议&#xff09; 原文地址&#xff1a;https://arxiv.org/abs/2301.12048 代码地址&#xff1a;https://github.com/wyzjack/MRMGA4VAD…

深入理解 Vue 中的指针操作(二)

文章目录 ☘️引言☘️基本用法&#x1f342;v-for指令&#x1f342;v-model指令&#x1f331;v-model适用表单控件 ☘️结论 ☘️引言 Vue.js 是一款非常流行且功能强大的前端框架&#xff0c;它以其响应式的数据绑定和组件化的开发方式赢得了众多开发者的喜爱。而在 Vue.js …

泗博Modbus转Profinet网关TS-180对水表流量的监控应用

应用场景&#xff1a; 陕西某工程技术有限公司在一民生工程项目中&#xff0c;需要对公园直饮水进行净化保证其水质。直饮水净化装置需根据用水量不定期的维护&#xff0c;通过统计各个净化装置净化的直饮水的流量&#xff0c;来实现提前维护目的。 应用痛点&#xff1a; 项目…

二叉树(判断是否为单值二叉树)

题目&#xff08;力扣&#xff09;&#xff1a; 判断二叉树上每个节点的值是否相同&#xff0c;就需要让root节点分别与左节点和右节点分别比较是否相同。 注意&#xff1a;root等于空时&#xff0c;直接可以返回true&#xff1b; 首先&#xff0c;先判断他的特殊情况&#x…

C++ day38 动态规划 斐波那契数列 爬楼梯 使用最小花费爬楼梯

题目1&#xff1a;509 斐波那契数列 题目链接&#xff1a;斐波那契数列 对题目的理解 斐波那契数列由0和1开始&#xff0c;后面每一项数字(F(n))都是前两个数字的和&#xff0c;给一个n&#xff0c;计算F(n)&#xff0c;&#xff08;0<n<30&#xff09; 动规五部曲 …

“Install Js dependencies failed“JS SDK安装失败【Bug已解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:解决措施1解决方案2:其他解决方案解决方案3:此Bug解决方案总结项目场景: 在下载JS SDK时,出现下载失败的情况,并显示“Install Js dependencies failed”。 在使用版本为DevEco Studio 3.0.0.601 Beta1进行低代码开发时…

Echarts-使用渐变色填充

垂直方向的渐变 color: {type: linear,// x0,y1,柱子的颜色在垂直方向渐变x: 0,y: 1,colorStops: [// 0%处的颜色{offset: 0,color: #12c2e9,},// 50%处的颜色{offset: 0.5,color: #c471ed,},// 100%处的颜色{offset: 1,color: #f64f59,},],global: false // 缺省为 false} 水…

力扣347. 前 K 个高频元素(java,最小堆,快速排序法)

Problem: 347. 前 K 个高频元素 文章目录 前言题目描述思路解题方法复杂度Code 前言 对于求取Top K一般有如下两种题型&#xff1a; 1.针对静态数据&#xff08;查询TopK操作&#xff09; 2.针对动态数据&#xff08;包括添加数据操作和查询TOPK操作&#xff09; 一般解决思路…

第22章 NIO编程

在本章中需要掌握NIO中的缓冲区的作用&#xff0c;并理解缓冲区中的数据处理模型&#xff0c;掌握Channel的作用&#xff0c;并结合缓冲区实现数据I/O操作&#xff0c;理解文件锁的作用&#xff0c;并且掌握字符编码处理支持类的使用&#xff0c;掌握Reactor设计模型&#xff0…

Electron+Ts+Vue+Vite桌面应用系列:sqlite增删改查操作篇

文章目录 1️⃣ sqlite应用1.1 sqlite数据结构1.2 初始化数据库1.3 初始化实体类1.4 操作数据类1.5 页面调用 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418 ElectronTsVueVite桌面应用系列 &#xff1a;这个系列包括了从桌…

【设计模式-2.2】创建型——简单工厂和工厂模式

说明&#xff1a;本文介绍设计模式中&#xff0c;创建型设计模式中的工厂模式&#xff1b; 飞机大战 创建型设计模式&#xff0c;关注于对象的创建&#xff0c;本文介绍的简单工厂和工厂模式同样也是。举一个游戏例子&#xff0c;如飞机大战游戏中&#xff0c;屏幕中敌人类型…

【开题报告】海洋多源数据质量控制应用服务的WebServer设计与实现

开 题 报 告 内 容 论文选题的意义、主要研究内容和文献资料调研情况 一、选题意义 在当今世界研究自然环境的大背景下&#xff0c;计算机技术与各学科、各领域的综合应用逐渐增多。作为地球上最广阔的水体&#xff0c;同时也是地球上决定气候发展的主要的因素之一&#xff0…

Unity学习笔记11

一、视频播放功能 1.如何让视频在游戏场景中播放&#xff1f; 在Assets目录下添加一个渲染器纹理&#xff0c;步骤&#xff1a;新建→渲染器纹理 首先在创建一个平面&#xff0c;想让视频在平面上显示。在平面上添加一个组件 Video Player 然后将视频文件拖拽到视频剪辑位置上…

自动化测试 —— requests和selenium模块!

一、requests基于POST请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #1.requests的GET与POST用法的区别&#xff1a; GET请求: (HTTP默认的请求方法就是GET) * 没有请求体 * 数据必须在1K之内&#xff01; * GET请求数据会暴露在浏览器…

【MyBatis】MyBatis操作数据库

目录 一&#xff0c;准备工作 1.1 创建工程 1.2 准备数据 1.3 数据库连接字符串 1.4 创建持久层接口UserInfoMapper 1.5 单元测试 二&#xff0c;注解的基础操作 2.1 打印日志 2.2 参数传递 2.3 增&#xff08;Insert&#xff09; 2.4 删&#xff08;Delete&#x…

pytest分布式执行(pytest-xdist)

前言 平常我们手工测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟。如果一个测试人员执行需要1000分钟才能执行完&#xff0c;当项目非常紧急的时候&#xff0c;我们会用测试人力成本换取时间成本&#xff0c;这个时候多找个小伙伴把任务…

如何使用群晖Synology Office结合内网穿透实现多人远程编辑文件协同办公

使用群晖Synology Office提升生产力&#xff1a;多人同时编辑一个文件 文章目录 使用群晖Synology Office提升生产力&#xff1a;多人同时编辑一个文件本教程解决的问题是&#xff1a;1. 本地环境配置2. 制作本地分享链接3. 制作公网访问链接4. 公网ip地址访问您的分享相册5. 制…

react-route-dom 实现简单的嵌套路由

最终效果 点击 to test1 点击to test2 > to test21 点击to test2 > to test22 代码如下 path: "page",element: <父组件 />,children: [{ path: "test1", element: <Test1 /> },{path: "test2",element: <Test2 />…

【JavaEE初阶】死锁问题

目录 一、死锁的三种典型场景 1、一个线程&#xff0c;一把锁 2、两个线程&#xff0c;两把锁 3、N个线程&#xff0c;M把锁 死锁&#xff0c;是多线程代码中的一类经典问题。我们知道加锁是能解决线程安全问题的&#xff0c;但是如果加锁的方式不当&#xff0c;就可能产生死…