【QT5】<应用> 小游戏:贪吃蛇
文章目录
一、项目要求
二、需求分析
三、实现效果
四、代码
一、项目要求
【1】主要实现:游戏界面存在一条蛇🐍,使用键盘wsad或者↑↓←→键盘可以控制蛇的行走方向。同时界面中会随机出现食物,蛇可以吃食物,然后蛇的身体就会变长。吃完一个食物之后才会刷新另外一个食物。
【2】游戏结束:蛇碰壁。
【3】玩家分数:由蛇的存活时间以及长度综合计算。time为蛇存活的秒数,lent-len0表示蛇增加的节点数量。同时,玩家分数需要实时显示。
【4】重新开始:点击相应的按钮。
【5】加速模式:双击键盘可以加速蛇的移动。例如按两下w键,蛇的速度变为原来的2倍。
【6】不同食物:食物有多种类别,不同的食物会导致蛇变长的长度不同。
二、需求分析
【1】针对主要实现:
- 创建蛇(Snake)、食物(Food)和主要窗口(Widget)类。
- Snake类:创建方法来实现蛇的移动(头插一个,尾删一个)、蛇的方向检测(根据键盘值)、蛇是否死亡(是否碰壁)以及在窗口中绘制蛇(通过传入painter)。
- Food类:创建方法来实现食物的坐标生成和类型生成(利用随机数)、在窗口中绘制食物。用type整型变量来标志食物类型,当type=1时蛇吃掉后加1节,当type=2时蛇吃掉后加2节,以此类推。
- Widget类:创建方法来实现整体的按键检测、绘制图像、计算玩家分数。为了让蛇不断移动,使用定时器(QTimer)来周期性触发槽函数,在槽函数中执行蛇吃食物、食物更新、画面更新等操作。
- 按键控制:①↑↓←→键盘控制蛇的移动;②空格键控制游戏的开始/暂停(控制定时器开始/停止)。
- 综合不同类的绘图:将主要逻辑的Widget类中实例化的painter对象作为形参传入Snake和Food类中,在它们各自的方法中进行各自的绘图操作。
【2】针对重新开始:
- 在ui设计器中添加QPushButton,并添加相应的槽函数。
- 槽函数中将分数、暂停标志、时间计数器等属性恢复初始值。
- 槽函数中将已有的蛇、食物对象delete,再创建新的蛇、食物对象。
- 槽函数中需要重新聚焦于gameWidget,否则点击按钮后需要再点击gameWidget才能检测键盘的输入。重新聚焦调用"ui->gameWidget->setFocus();"
【3】针对不同速度:
- 在Snake类中创建属性speed,当speed为1时表示每次触发定时器槽函数执行蛇前进1格,当speed为2时表示每次触发定时器槽函数执行蛇前进2格。
- 初始化speed为1,当用户手动按下两下↑后会加速,直到用户改变蛇的方向。
【4】针对不同食物:
- 在Food类中创建属性type,当type为1时表示食物类型为1(蛇吃后增加1节),当type为2时表示食物类型为2(蛇吃后增加2节),当type为3时表示食物类型为3(蛇吃后增加3节)。
- 类型1设定为绿色的圆形。
- 类型2设定为深蓝色的椭圆。
- 类型3设定为浅蓝色的方形。
三、实现效果
四、代码
【1】food.h:
#ifndef FOOD_H
#define FOOD_H#include <QWidget>
#include <QPainter>
#include <QRandomGenerator>/************************************************************ @类名: Food* @摘要: 食物类* @作者: 柯同学* @注意: 三种食物类型:type值为几就加几节蛇身*********************************************************/
class Food : public QWidget
{Q_OBJECT
public:explicit Food(QWidget *parent = nullptr);int getX(); //返回食物横坐标int getY(); //返回食物纵坐标int getRadius(); //返回食物半径int getType(); //返回食物类型void generateFood();//生成食物的坐标和类型void paintFood(QPainter &painter);//绘制食物private:int foodX; //食物横坐标int foodY; //食物纵坐标int radius; //食物半径int type; //食物类型:1类型为增加1节,2类型增加2节,3类型增加3节
};#endif // FOOD_H
【2】food.cpp:
#include "food.h"/************************************************************ @函数名:Food* @功 能:食物类的构造函数* @参 数:parent父对象* @返回值:无*********************************************************/
Food::Food(QWidget *parent): QWidget(parent), radius(15)
{//初始的食物也随机generateFood();
}/************************************************************ @函数名:getX* @功 能:返回食物的横坐标* @参 数:无* @返回值:食物的横坐标*********************************************************/
int Food::getX()
{return foodX;
}/************************************************************ @函数名:getY* @功 能:返回食物的纵坐标* @参 数:无* @返回值:食物的纵坐标*********************************************************/
int Food::getY()
{return foodY;
}/************************************************************ @函数名:getRadius* @功 能:返回食物的半径* @参 数:无* @返回值:食物的半径*********************************************************/
int Food::getRadius()
{return radius;
}/************************************************************ @函数名:getType* @功 能:返回食物的类型* @参 数:无* @返回值:食物的类型*********************************************************/
int Food::getType()
{return type;
}/************************************************************ @函数名:generateFood* @功 能:随机生成食物的坐标、类型* @参 数:无* @返回值:无*********************************************************/
void Food::generateFood()
{//随机生成坐标,距边界radius降低反应难度foodX = QRandomGenerator::global()->bounded(10 + radius, 580 - radius * 2);foodY = QRandomGenerator::global()->bounded(20 + radius, 570 - radius * 2);//随机生成类型[1,4)type = QRandomGenerator::global()->bounded(1, 4);
}/************************************************************ @函数名:paintFood* @功 能:根据食物类型的不同,绘制不同的食物类型。* @参 数:painter---画家对象* @返回值:无* @说 明:type=1---类型1:绿色的圆形* type=2---类型2:深蓝色的椭圆形* type=3---类型3:淡蓝色的矩形*********************************************************/
void Food::paintFood(QPainter &painter)
{QPen pen;QBrush brush;//根据type不同,绘制不同的食物switch (this->type){case 1:pen.setColor(QColor(43, 220, 112));brush.setColor(QColor(43, 220, 112));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawEllipse(QRect(foodX, foodY, radius, radius));break;case 2:pen.setColor(QColor(0, 62, 146));brush.setColor(QColor(0, 62, 146));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawEllipse(QRect(foodX, foodY, radius*2, radius));break;case 3:pen.setColor(QColor(29, 130, 154));brush.setColor(QColor(29, 130, 154));brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawRect(QRect(foodX, foodY, radius, radius));break;}
}
【3】snake.h:
#ifndef SNAKE_H
#define SNAKE_H#include <QWidget>
#include <QEvent>
#include <QPaintEvent>
#include <QPainter>//枚举蛇前进的方向
enum Direct{MOVE_UP,MOVE_DOWN,MOVE_LEFT,MOVE_RIGHT
};/************************************************************ @类名: Snake* @摘要: 蛇类* @作者: 柯同学* @注意: 有两种速度:speed为1就每次timeout前进1格,以此类推。* 在原有方向的基础上,再次按原方向键能切换到二倍速模式,* 比如蛇在往上,再次按up键就两倍速,直到切换方向。*********************************************************/
class Snake : public QWidget
{Q_OBJECT
public:explicit Snake(QWidget *parent = nullptr);void paintSnake(QPainter &painter); //绘制蛇身void keyPress(QKeyEvent *event); //键盘控制移动方向void autoMove(); //沿着方向自动移动void frontAddBody(); //根据方向增加首节点QRect getSnakeHead(); //获取蛇的首节点信息int getLength(); //返回蛇身节点个数bool isOver(); //返回蛇是否死亡,死亡为trueprivate:QList<QRect> body; //蛇身int nodeWidth; //节点宽度int nodeHeight; //节点高度int moveDirect; //移动方向int speed; //移动速度:1表示默认速度,2表示两倍速度
};#endif // SNAKE_H
【4】snake.cpp:
#include "snake.h"/************************************************************ @函数名:Snake* @功 能:蛇的构造函数* @参 数:parent---父对象* @返回值:无* @说 明:初始化三节蛇身*********************************************************/
Snake::Snake(QWidget *parent): QWidget(parent), nodeWidth(20), nodeHeight(20), moveDirect(MOVE_LEFT), speed(1)
{//初始给定三节蛇身body.append(QRect(400, 300, nodeWidth, nodeHeight));body.append(QRect(400 + nodeWidth, 300, nodeWidth, nodeHeight));body.append(QRect(400 + nodeWidth * 2, 300, nodeWidth, nodeHeight));
}/************************************************************ @函数名:getLength* @功 能:获取蛇身的长度,即有几个节点* @参 数:无* @返回值:蛇身的长度*********************************************************/
int Snake::getLength()
{return body.length();
}/************************************************************ @函数名:isOver* @功 能:判定蛇是否碰墙死亡* @参 数:无* @返回值:true---蛇死亡,false---蛇没有死亡*********************************************************/
bool Snake::isOver()
{if (body[0].y() <= 20 || body[0].y() + nodeHeight >= 570 ||body[0].x() <= 10 || body[0].x() + nodeWidth >= 580) {return true;}return false;
}/************************************************************ @函数名:keyPress* @功 能:按键检测,控制蛇的前进方向* @参 数:event---按键的事件* @返回值:无* @说 明:在原有方向的基础上,再次按原方向键能切换到二倍速模式*********************************************************/
void Snake::keyPress(QKeyEvent *event)
{switch(event->key()) {case Qt::Key_Up://蛇往上if (MOVE_UP == moveDirect){speed = 2;}else if (moveDirect != MOVE_DOWN){moveDirect = MOVE_UP;speed = 1;}break;case Qt::Key_Down://蛇往下if (MOVE_DOWN == moveDirect){speed = 2;}else if (moveDirect != MOVE_UP){moveDirect = MOVE_DOWN;speed = 1;}break;case Qt::Key_Left://蛇往左if (MOVE_LEFT == moveDirect){speed = 2;}else if (moveDirect != MOVE_RIGHT){moveDirect = MOVE_LEFT;speed = 1;}break;case Qt::Key_Right://蛇往右if (MOVE_RIGHT == moveDirect){speed = 2;}else if (moveDirect != MOVE_LEFT){moveDirect = MOVE_RIGHT;speed = 1;}break;default:break;}
}/************************************************************ @函数名:autoMove* @功 能:根据speed属性,让蛇前进1格或2格* @参 数:无* @返回值:无* @说 明:蛇的前进做法:每次头插一个节点,删除最后的一个节点*********************************************************/
void Snake::autoMove()
{if (1 == speed){frontAddBody();body.removeLast();}else if (2 == speed){frontAddBody();frontAddBody();body.removeLast();body.removeLast();}
}/************************************************************ @函数名:frontAddBody* @功 能:根据前进方向,头插不同位置的节点* @参 数:无* @返回值:无* @说 明:由于碰壁就死亡了,无需越界判定*********************************************************/
void Snake::frontAddBody()
{switch (moveDirect){case MOVE_UP:body.insert(0, QRect(body[0].x(), body[0].y() - nodeHeight, nodeWidth, nodeHeight));break;case MOVE_DOWN:body.insert(0, QRect(body[0].x(), body[0].y() + nodeHeight, nodeWidth, nodeHeight));break;case MOVE_LEFT:body.insert(0, QRect(body[0].x() - nodeWidth, body[0].y(), nodeWidth, nodeHeight));break;case MOVE_RIGHT:body.insert(0, QRect(body[0].x() + nodeWidth, body[0].y(), nodeWidth, nodeHeight));break;}
}/************************************************************ @函数名:getSnakeHead* @功 能:返回首节点的拷贝,以防外界修改。* @参 数:无* @返回值:无*********************************************************/
QRect Snake::getSnakeHead()
{return body[0];
}/************************************************************ @函数名:paintSnake* @功 能:绘制蛇身,遍历QList* @参 数:painter---画家对象* @返回值:无*********************************************************/
void Snake::paintSnake(QPainter &painter)
{//设置painterQPen pen(QColor(64, 65, 66));QBrush brush(QColor(183, 1, 1));painter.setPen(pen);painter.setBrush(brush);//绘制蛇身for (int i = 0; i < body.length(); ++i) {painter.drawRect(body[i]);}
}
【5】widget.h:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "snake.h"
#include "food.h"
#include <QPainter>
#include <QTimer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE/************************************************************ @类名: Widget* @摘要: 主要界面类* @作者: 柯同学* @注意: 在该类中进行蛇吃食物、游戏结束等逻辑的实现*********************************************************/
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void paintEvent(QPaintEvent *event) override; //绘图void keyPressEvent(QKeyEvent *event) override; //按键检测void snakeEatFood(); //蛇吃食物,更新食物void computeScore(); //计算玩家分数private slots:void timeOut(); //定时器触发的槽函数void on_pushButton_clicked();//"重新开始"按钮的槽函数private:Ui::Widget *ui;Snake *snake; //蛇Food *food; //食物QTimer *timer; //定时器,固定100ms触发bool isPause; //开始或暂停的标志,true为暂停int timerCount; //定时器触发次数double score; //玩家分数
};
#endif // WIDGET_H
【6】widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>/************************************************************ @函数名:Widget* @功 能:主要窗口的构造函数* @参 数:parent---父对象* @返回值:无*********************************************************/
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), isPause(true), timerCount(0), score(0)
{ui->setupUi(this);//实例化蛇snake = new Snake(ui->gameWidget);//实例化食物food = new Food(ui->gameWidget);//设置定时器timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(timeOut()));//设置聚焦对象ui->gameWidget->setFocus();
}/************************************************************ @函数名:~Widget* @功 能:主要窗口的析构函数* @参 数:无* @返回值:无* @说 明:由于QT的对象树机制,绑定好父对象后无需手动delete其他空间*********************************************************/
Widget::~Widget()
{delete ui;
}/************************************************************ @函数名:~Widget* @功 能:主要窗口的析构函数* @参 数:无* @返回值:无*********************************************************/
void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event)QPainter painter(this);//判定游戏是否结束,结束则显示提示if (snake->isOver()) {//蛇死亡,游戏结束timer->stop();isPause = true;QFont font("宋体", 30, QFont::ExtraBold,false);painter.setFont(font);QRect showArea(200, 250, 200, 100);painter.drawText(showArea, Qt::AlignHCenter | Qt::AlignVCenter, "游戏结束!");}//绘制蛇和食物snake->paintSnake(painter);food->paintFood(painter);//实时显示玩家分数ui->scoreLabel->setText("分数: " + QString::number(score));
}/************************************************************ @函数名:keyPressEvent* @功 能:重写的按键检测事件函数* @参 数:event---按键事件* @返回值:无* @说 明:以防游戏结束后还能控制,首先需要判定游戏是否结束*********************************************************/
void Widget::keyPressEvent(QKeyEvent *event)
{//游戏未结束才进行按键控制if (!(snake->isOver())) {//按键控制蛇移动snake->keyPress(event);//按键控制暂停if (event->key() == Qt::Key_Space) {if (isPause){isPause = false;timer->start(100);}else {isPause = true;timer->stop();}}}
}/************************************************************ @函数名:snakeEatFood* @功 能:蛇与食物接触,则给蛇加节点,给食物重新生成坐标和类型* @参 数:无* @返回值:无* @说 明:生成食物必须放在蛇加节点之后*********************************************************/
void Widget::snakeEatFood()
{//蛇与食物接触if (abs(snake->getSnakeHead().x() - food->getX()) <= food->getRadius() &&abs(snake->getSnakeHead().y() - food->getY()) <= food->getRadius()){//蛇吃不同类型食物加不同节int count = food->getType();while (count--){snake->frontAddBody();}//再次生成食物food->generateFood();}
}/************************************************************ @函数名:computeScore* @功 能:计算玩家分数* @参 数:无* @返回值:无* @说 明:分数由两部分构成:时间分数、长度分数。* 每坚持1秒,分数增加1分。* 每多一节身体,分数增加10分。*********************************************************/
void Widget::computeScore()
{double timeScore = (timerCount / 10.0) * 1; //时间的分数,每秒1分int lenScore = (snake->getLength() - 3) * 10; //长度的分数,增一节10分if (lenScore >= 0)this->score = timeScore + lenScore;
}/************************************************************ @函数名:timeOut* @功 能:定时器的槽函数* @参 数:无* @返回值:无*********************************************************/
void Widget::timeOut()
{//蛇自动移动,吃食物snake->autoMove();snakeEatFood();//计算玩家分数timerCount++;computeScore();//更新界面this->update();
}/****************************************************************** @函数名:on_pushButton_clicked* @功 能:"重新开始"按钮的槽函数* @参 数:无* @返回值:无* @说 明:需要重新聚焦于gameWidget,否则点击按钮后需要再点击gameWidget***************************************************************/
void Widget::on_pushButton_clicked()
{//清除相关属性timerCount = 0; //定时器计数清零score = 0; //分数清零isPause = true; //恢复暂停//删除已有成员对象if (snake) {delete snake;}if (food) {delete food;}//创建新对象snake = new Snake(ui->gameWidget);food = new Food(ui->gameWidget);//更新界面this->update();ui->gameWidget->setFocus();//重新聚焦于游戏窗口
}
【7】main.cpp: 系统自动生成的,没有改动。
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
相关文章:

【QT5】<应用> 小游戏:贪吃蛇
文章目录 一、项目要求 二、需求分析 三、实现效果 四、代码 一、项目要求 【1】主要实现:游戏界面存在一条蛇🐍,使用键盘wsad或者↑↓←→键盘可以控制蛇的行走方向。同时界面中会随机出现食物,蛇可以吃食物,然后…...

【Webpack】使用 Webpack 构建 Vue3+TS 项目
构建项目目录 tsc --init npm init -yshim.d.ts 文件是一个类型声明文件,用于告诉 TypeScript 编译器如何处理 Vue 的单文件组件(SFC)和其他自定义模块。为 Vue 的单文件组件和其他非 TypeScript 模块提供类型信息,以便在 TypeScr…...

数据防泄漏的六个步骤|数据防泄漏软件有哪些
在当前复杂多变的网络安全环境下,数据防泄漏软件成为了企业信息安全架构中不可或缺的一环。下面以安企神软件为例,告诉你怎么防止数据泄露,以及好用的防泄露软件。 1. 安企神软件 安企神软件是当前市场上备受推崇的企业级数据防泄漏解决方案…...

SpringCloud 网关Gateway配置并使用
目录 1 什么是网关? 2 Gateway的使用 2.1 在其pom文件中引入依赖 2.2 然后gateway配置文件中配置信息 2.3 启动网关微服务 3 网关处理流程 4 前端-网关-微服务-微服务间实现信息共享传递 1 什么是网关? 网关:就是网络的关口ÿ…...

MySQl基础----Linux下搭建mysql软件及登录和基本使用(附实操图超简单一看就会)
绪论 涓滴之水可磨损大石,不是由于他力量强大,而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力,才能够获得那些技巧。 ——贝多芬。新开MySQL篇章,本章非常基础包括如何在Linux上搭建(当然上面的SQL语句你在其他能执行…...

PostgreSQL17优化器改进(4)允许UNION(没有ALL)使用MergeAppend
PostgreSQL17优化器改进(4)允许UNION(没有ALL)使用MergeAppend UNION存在的问题 到PostgreSQL16.3版本为止,UNION执行计划通常不是最优的,优化器有两种处理方法: 优化器只考虑使用Append节点并通过使用Hash Aggregate,Append -…...

SSM 基于大数据技术的创业推荐系统-计算机毕业设计源码02979
摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作…...

基于WPF技术的换热站智能监控系统03--实现左侧加载动画
1、左侧布局规划 左侧分5行,每行的高度通过height属性来指定,1.2*表示占1.2倍的宽度 2、创建用户控件 在WPF中想要进行个性化处理,主要可以通过三个方面来实现:控件模板(控件模板、数据模板、数据容器模板)…...

4D毫米波雷达技术及发展
文章目录 前言一、4D毫米波雷达是什么?二、毫米波雷达是什么?毫米波雷达的基本原理多普勒效应 前言 现阶段自动驾驶技术中,主要用到的传感器有摄像头、激光雷达和毫米波雷达。 摄像头的光谱从可见光到红外光谱,是最接近人眼的传感…...

请解释Java Web应用的开发流程,包括前后端分离和交互方式。请解释Java中的锁分离技术,并讨论其在提高并发性能方面的作用。
请解释Java Web应用的开发流程,包括前后端分离和交互方式。 Java Web应用的开发流程是一个涵盖多个阶段的过程,这些阶段从需求分析开始,经过设计、编码、测试,最终到部署和维护。在这个过程中,前后端分离成为现代Web应…...

selenium使用已经打开的浏览器
Selenium 本身不支持直接连接到一个已经打开的浏览器页面。Selenium 启动的浏览器实例是一个全新的会话,它与手动打开的浏览器页面是分开的。但是,有一些变通的方法可以实现类似的效果。 一种方法是通过附加代理连接到已经打开的浏览器。下面是如何实现…...

Redis: 深入解析高性能内存数据库的实现原理
一、Redis简介 Redis是一种基于内存的键值存储数据库,支持丰富的数据类型,如字符串、列表、集合、有序集合和哈希表。它不仅具有极高的性能,还支持数据持久化、主从复制和分布式架构,使其在各种应用场景中表现出色。 1.1 Redis的…...

使用 Python进行自动备份文件
文件备份对数据保护至关重要,让我们使用 shutil 模块创建一个简单的备份脚本 这段代码的作用就是将指定源目录中的所有文件备份到目标备份目录中,并在备份目录中创建带有时间戳的子目录,通过定期运行这段代码,可以实现自动备份文…...

02_01_SpringMVC初识
一、回顾MVC三层架构 1、什么是MVC三层 MVC是 模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。主要作用是降低视图与业务逻辑之间的双向耦合,它不是一种…...

Python学习打卡:day04
day4 笔记来源于:黑马程序员python教程,8天python从入门到精通,学python看这套就够了 目录 day428、while 循环的嵌套应用29、while 循环案例 — 九九乘法表补充知识示例:九九乘法表 30、for 循环基本语法while 和 for 循环对比f…...

gitlab问题记录
You wont be able to pull or push project code via SSH until you add an SSH key to you 解决方案:https://blog.csdn.net/gufenchen/article/details/95663284...

OpenCV练习(1)签名修复
1.目的 在学校的学习过程中,需要递交许多材料,且每份材料上都需要对应负责人签名,有时候找别人要签名,然后自己粘贴的话,会出现签名模糊,背景不是纯白透明。为此以word中的“颜色校正”功能为参照…...

软设之系统测试之测试的基本概念及分类
测试的基本概念 尽早,不断地进行测试 程序员避免测试自己设计的程序 既要选择有效,合理的数据,也要选择无效,不合理的数据 修改后应进行回归测试 尚未发现的错误数量与该程序已发现错误其他成正比。 动态测试 黑盒测试(测试…...

Python学习打卡:day06
day6 笔记来源于:黑马程序员python教程,8天python从入门到精通,学python看这套就够了 目录 day648、函数综合案例49、数据容器入门50、列表的定义语法51、列表的下标索引1、列表的下标(索引)2、列表的下标(…...

支付宝 沙盒demo使用
简介:支付宝沙箱环境是一个为开发者提供的模拟测试环境,用于在应用上线前进行接口功能开发和联调。在这个环境中,开发者可以模拟开放接口,进行开发调试工作,以确保应用上线后能顺利运行。 1. 配置沙盒 1. 1 沙箱控制…...

ConcurrentHashMap如何保证线程安全?
ConcurrentHashMap 是 HashMap 的多线程版本,HashMap 在并发操作时会有各种问题,比如死循环问题、数据覆盖等问题。而这些问题,只要使用 ConcurrentHashMap 就可以完美解决了,那问题来了,ConcurrentHashMap 是如何保证…...

spring属性注入的不细心错误
属性注入问题 个人博客:www.zgtsky.top 同个的对象,在一个类中注入成功,在另一个类中注入为null 问题:在检测各个需要的类上已经打上注解后,出现了在一个类A1中注入B属性成功了,但在另一个类A2中注入B属性却失败了。…...

JVM 根可达算法
Java中的垃圾 Java中"垃圾"通常指的是不再被程序使用和引用的对象,具体表现在没有被栈、JNI指针和永久代对象所引用的对象。Java作为一种面向对象的编程语言,它使用自动内存管理机制,其中垃圾收集器负责检测和回收不再被程序引用的…...

Kafka基础架构与核心概念?有哪些应用场景?
Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。架构特点是分区、多副本、多生产者、多订阅者,性能特点主要是高吞吐,低时延。 Kafka主要设计…...

内网不能访问网站怎么办?
内网不能访问网站是在网络使用过程中常见的问题之一。当我们使用局域网连接时,有时候会遇到无法访问特定网站的情况。这可能是因为网络环境复杂,或者受到了某些限制。本篇文章将介绍一种解决内网不能访问网站问题的产品——天联组网。 天联组网是一款由…...

python-求f(x,n)
[题目描述] 输入: 输入 𝑥和 𝑛。输出: 函数值,保留两位小数。样例输入1 4.2 10 样例输出1 3.68 来源/分类(难度系数:一星) 完整代码如下: x,nmap(eval,input().split(…...

java值jsp语法笔记
1 JSP注释 1.1 显示注释 显示注释会出现在生成的HTML文档中,对用户可见。 <!-- 这是一个HTML显示注释 --> 1.2 隐式注释 隐式注释不会出现在生成的HTML文档中,对用户不可见。 <%-- 这是一个JSP隐式注释 --%> 2 JSP脚本元素 2.1 局部…...

057、PyCharm 运行代码报错:Error Please select a valid Python interpreter
当我们在PyCharm运行代码时,提示如下图错误: 那么问题通常是由于PyCharm未正确配置Python解释器引起的。 我们只需按以下步骤重新配置Python解释器即可: 打开PyCharm设置: 在菜单栏中的点击 “File” -> “Settings”…...

Java实现图书管理系统
一、引言 本篇介绍了一个简易的图书管理系统,面向管理员和普通用户分别给出了不同的菜单,实现了一些基本的图书操作功能,包括图书的增删查改、借阅、归还等 二、图书管理系统框架 图书管理系统,顾名思义,管理的是图…...

使用静态方法接受对象参数
我们先来看一个例子 public class MyInteger { private int value; // 构造函数 public MyInteger(int value) { this.value value; } // 实例方法 public boolean isEven() { return value % 2 0; } // 静态方法接受int参数 public static boolean isEvenStatic…...