使用Java制作贪吃蛇小游戏

在这篇文章中,我将带你一步步实现一个经典的贪吃蛇小游戏。我们将使用Java语言和Swing库来构建这个游戏,它包含了贪吃蛇游戏的基本功能:蛇的移动、吃食物、计分以及游戏结束判定。

游戏设计思路

贪吃蛇游戏的基本原理是:玩家控制一条蛇在屏幕上移动,蛇会吃随机出现的食物,每吃一次食物蛇就会变长一节,同时玩家得分增加。如果蛇撞到墙壁或自己的身体,游戏就结束。

我们将使用面向对象的方法设计这个游戏,主要包含以下几个类:

  • SnakeGame:游戏主类,负责初始化游戏窗口和游戏循环
  • GamePanel:游戏面板类,继承自JPanel,负责绘制游戏界面和处理游戏逻辑
  • Snake:蛇类,管理蛇的位置、移动和状态
  • Food:食物类,管理食物的位置和生成

下面让我们开始实现这个游戏吧!

第一步:创建游戏主类

首先,我们需要创建一个主类来启动游戏。这个类将设置游戏窗口并启动游戏循环。

import javax.swing.JFrame;public class SnakeGame {public static void main(String[] args) {// 创建游戏窗口JFrame frame = new JFrame("贪吃蛇游戏");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setResizable(false);// 创建游戏面板并添加到窗口GamePanel gamePanel = new GamePanel();frame.add(gamePanel);// 调整窗口大小以适应游戏面板frame.pack();// 居中显示窗口frame.setLocationRelativeTo(null);// 显示窗口frame.setVisible(true);// 启动游戏gamePanel.startGame();}
}

这个类很简单,它创建了一个JFrame窗口,并将游戏面板添加到窗口中。然后设置窗口的基本属性,最后调用游戏面板的startGame()方法来启动游戏。

第二步:创建游戏面板类

接下来,我们创建游戏面板类,它将继承自JPanel,并实现游戏的主要逻辑和绘制功能。

import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {// 游戏区域的尺寸private static final int WIDTH = 600;private static final int HEIGHT = 600;// 蛇和食物的大小private static final int UNIT_SIZE = 20;// 游戏区域的单元数量private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);// 游戏速度控制private static final int DELAY = 75;// 蛇的身体部分位置数组private final int[] x = new int[GAME_UNITS];private final int[] y = new int[GAME_UNITS];// 蛇的初始长度private int bodyParts = 6;// 吃掉的食物数量private int applesEaten;// 食物的位置private int appleX;private int appleY;// 蛇的移动方向private char direction = 'R'; // 初始向右移动private boolean running = false;private Timer timer;public GamePanel() {// 设置面板属性setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);// 添加键盘监听器addKeyListener(this);// 初始化游戏initGame();}public void initGame() {// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * UNIT_SIZE;y[i] = 50;}// 生成第一个食物newApple();// 启动游戏running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 绘制网格(可选,仅用于辅助查看)for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 绘制食物g.setColor(Color.RED);g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);// 绘制蛇for (int i = 0; i < bodyParts; i++) {if (i == 0) {// 蛇头g.setColor(Color.GREEN);} else {// 蛇身g.setColor(new Color(45, 180, 0));// 或者使用不同颜色创建渐变效果// g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255)));}g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);}// 绘制分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void newApple() {// 随机生成食物位置appleX = (int)(Math.random() * (WIDTH / UNIT_SIZE)) * UNIT_SIZE;appleY = (int)(Math.random() * (HEIGHT / UNIT_SIZE)) * UNIT_SIZE;// 确保食物不会出现在蛇身上for (int i = 0; i < bodyParts; i++) {if ((x[i] == appleX) && (y[i] == appleY)) {newApple();}}}public void move() {// 移动蛇的身体部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根据方向移动蛇头switch (direction) {case 'U':y[0] = y[0] - UNIT_SIZE;break;case 'D':y[0] = y[0] + UNIT_SIZE;break;case 'L':x[0] = x[0] - UNIT_SIZE;break;case 'R':x[0] = x[0] + UNIT_SIZE;break;}}public void checkApple() {// 检查蛇头是否碰到食物if ((x[0] == appleX) && (y[0] == appleY)) {bodyParts++;applesEaten++;newApple();}}public void checkCollisions() {// 检查蛇头是否碰到自己的身体for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {running = false;}}// 检查蛇头是否碰到左边界if (x[0] < 0) {running = false;}// 检查蛇头是否碰到右边界if (x[0] >= WIDTH) {running = false;}// 检查蛇头是否碰到上边界if (y[0] < 0) {running = false;}// 检查蛇头是否碰到下边界if (y[0] >= HEIGHT) {running = false;}// 如果游戏结束,停止计时器if (!running) {timer.stop();}}public void gameOver(Graphics g) {// 绘制游戏结束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);// 绘制最终分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 绘制重新开始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);}public void startGame() {initGame();}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {move();checkApple();checkCollisions();}repaint();}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();// 根据按键改变蛇的移动方向,但不能直接反向移动switch (key) {case KeyEvent.VK_LEFT:if (direction != 'R') {direction = 'L';}break;case KeyEvent.VK_RIGHT:if (direction != 'L') {direction = 'R';}break;case KeyEvent.VK_UP:if (direction != 'D') {direction = 'U';}break;case KeyEvent.VK_DOWN:if (direction != 'U') {direction = 'D';}break;case KeyEvent.VK_SPACE:if (!running) {startGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}

这个类是游戏的核心部分,它处理了游戏的主要逻辑:

  1. 游戏面板的初始化和设置
  2. 游戏循环的控制(通过Timer实现)
  3. 游戏元素的绘制(蛇、食物和分数)
  4. 蛇的移动和方向控制
  5. 食物的生成和检测
  6. 碰撞检测(包括边界和自身)
  7. 游戏结束的处理

第三步:改进游戏结构(可选)

上面的实现已经可以运行一个简单的贪吃蛇游戏了,但代码结构还可以进一步优化。我们可以将蛇和食物单独封装成类,使代码更加模块化。

以下是优化后的代码结构:

// Snake.java
public class Snake {private int[] x;private int[] y;private int bodyParts;private char direction;public Snake() {x = new int[GamePanel.GAME_UNITS];y = new int[GamePanel.GAME_UNITS];bodyParts = 6;direction = 'R';// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * GamePanel.UNIT_SIZE;y[i] = 50;}}// Getters and setterspublic int[] getX() { return x; }public int[] getY() { return y; }public int getBodyParts() { return bodyParts; }public char getDirection() { return direction; }public void setDirection(char direction) { this.direction = direction; }public void move() {// 移动蛇的身体部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根据方向移动蛇头switch (direction) {case 'U':y[0] = y[0] - GamePanel.UNIT_SIZE;break;case 'D':y[0] = y[0] + GamePanel.UNIT_SIZE;break;case 'L':x[0] = x[0] - GamePanel.UNIT_SIZE;break;case 'R':x[0] = x[0] + GamePanel.UNIT_SIZE;break;}}public void grow() {bodyParts++;}public boolean checkSelfCollision() {// 检查蛇头是否碰到自己的身体for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {return true;}}return false;}public boolean checkBoundaryCollision() {// 检查蛇头是否碰到边界return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;}
}// Food.java
import java.util.Random;public class Food {private int x;private int y;private Random random;public Food() {random = new Random();newPosition();}public void newPosition() {// 随机生成食物位置x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;}// Getterspublic int getX() { return x; }public int getY() { return y; }public boolean isEaten(Snake snake) {// 检查食物是否被蛇吃掉return snake.getX()[0] == x && snake.getY()[0] == y;}
}

使用这些类重构后的GamePanel类:

// 优化后的GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {private static final int WIDTH = 600;private static final int HEIGHT = 600;private static final int UNIT_SIZE = 20;private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);private static final int DELAY = 75;private Snake snake;private Food food;private int applesEaten;private boolean running = false;private Timer timer;public GamePanel() {setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);addKeyListener(this);initGame();}public void initGame() {snake = new Snake();food = new Food();applesEaten = 0;running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 绘制网格for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 绘制食物g.setColor(Color.RED);g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);// 绘制蛇int[] snakeX = snake.getX();int[] snakeY = snake.getY();for (int i = 0; i < snake.getBodyParts(); i++) {if (i == 0) {g.setColor(Color.GREEN);} else {g.setColor(new Color(45, 180, 0));}g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);}// 绘制分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void gameOver(Graphics g) {// 绘制游戏结束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);// 绘制最终分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 绘制重新开始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {snake.move();checkFood();checkCollisions();}repaint();}public void checkFood() {if (food.isEaten(snake)) {snake.grow();applesEaten++;food.newPosition();}}public void checkCollisions() {if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {running = false;}if (!running) {timer.stop();}}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch (key) {case KeyEvent.VK_LEFT:if (snake.getDirection() != 'R') {snake.setDirection('L');}break;case KeyEvent.VK_RIGHT:if (snake.getDirection() != 'L') {snake.setDirection('R');}break;case KeyEvent.VK_UP:if (snake.getDirection() != 'D') {snake.setDirection('U');}break;case KeyEvent.VK_DOWN:if (snake.getDirection() != 'U') {snake.setDirection('D');}break;case KeyEvent.VK_SPACE:if (!running) {initGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}

完整代码

下面是完整的贪吃蛇游戏代码,包含了所有类的实现:

// SnakeGame.java
import javax.swing.JFrame;public class SnakeGame {public static void main(String[] args) {JFrame frame = new JFrame("贪吃蛇游戏");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setResizable(false);GamePanel gamePanel = new GamePanel();frame.add(gamePanel);frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);gamePanel.startGame();}
}// GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;public class GamePanel extends JPanel implements ActionListener, KeyListener {private static final int WIDTH = 600;private static final int HEIGHT = 600;private static final int UNIT_SIZE = 20;private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);private static final int DELAY = 75;private Snake snake;private Food food;private int applesEaten;private boolean running = false;private Timer timer;public GamePanel() {setPreferredSize(new Dimension(WIDTH, HEIGHT));setBackground(Color.BLACK);setFocusable(true);addKeyListener(this);initGame();}public void initGame() {snake = new Snake();food = new Food();applesEaten = 0;running = true;timer = new Timer(DELAY, this);timer.start();}@Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);draw(g);}public void draw(Graphics g) {if (running) {// 绘制网格for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);}// 绘制食物g.setColor(Color.RED);g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);// 绘制蛇int[] snakeX = snake.getX();int[] snakeY = snake.getY();for (int i = 0; i < snake.getBodyParts(); i++) {if (i == 0) {g.setColor(Color.GREEN);} else {g.setColor(new Color(45, 180, 0));}g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);}// 绘制分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());} else {gameOver(g);}}public void gameOver(Graphics g) {// 绘制游戏结束文本g.setColor(Color.RED);g.setFont(new Font("Ink Free", Font.BOLD, 75));FontMetrics metrics1 = getFontMetrics(g.getFont());g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);// 绘制最终分数g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 40));FontMetrics metrics2 = getFontMetrics(g.getFont());g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);// 绘制重新开始提示g.setColor(Color.WHITE);g.setFont(new Font("Ink Free", Font.BOLD, 20));FontMetrics metrics3 = getFontMetrics(g.getFont());g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);}@Overridepublic void actionPerformed(ActionEvent e) {if (running) {snake.move();checkFood();checkCollisions();}repaint();}public void checkFood() {if (food.isEaten(snake)) {snake.grow();applesEaten++;food.newPosition();}}public void checkCollisions() {if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {running = false;}if (!running) {timer.stop();}}public void startGame() {initGame();}@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch (key) {case KeyEvent.VK_LEFT:if (snake.getDirection() != 'R') {snake.setDirection('L');}break;case KeyEvent.VK_RIGHT:if (snake.getDirection() != 'L') {snake.setDirection('R');}break;case KeyEvent.VK_UP:if (snake.getDirection() != 'D') {snake.setDirection('U');}break;case KeyEvent.VK_DOWN:if (snake.getDirection() != 'U') {snake.setDirection('D');}break;case KeyEvent.VK_SPACE:if (!running) {initGame();}break;}}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}
}// Snake.java
public class Snake {private int[] x;private int[] y;private int bodyParts;private char direction;public Snake() {x = new int[GamePanel.GAME_UNITS];y = new int[GamePanel.GAME_UNITS];bodyParts = 6;direction = 'R';// 初始化蛇的位置for (int i = 0; i < bodyParts; i++) {x[i] = 100 - i * GamePanel.UNIT_SIZE;y[i] = 50;}}public int[] getX() { return x; }public int[] getY() { return y; }public int getBodyParts() { return bodyParts; }public char getDirection() { return direction; }public void setDirection(char direction) { this.direction = direction; }public void move() {// 移动蛇的身体部分for (int i = bodyParts; i > 0; i--) {x[i] = x[i - 1];y[i] = y[i - 1];}// 根据方向移动蛇头switch (direction) {case 'U':y[0] = y[0] - GamePanel.UNIT_SIZE;break;case 'D':y[0] = y[0] + GamePanel.UNIT_SIZE;break;case 'L':x[0] = x[0] - GamePanel.UNIT_SIZE;break;case 'R':x[0] = x[0] + GamePanel.UNIT_SIZE;break;}}public void grow() {bodyParts++;}public boolean checkSelfCollision() {// 检查蛇头是否碰到自己的身体for (int i = bodyParts; i > 0; i--) {if ((x[0] == x[i]) && (y[0] == y[i])) {return true;}}return false;}public boolean checkBoundaryCollision() {// 检查蛇头是否碰到边界return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;}
}// Food.java
import java.util.Random;public class Food {private int x;private int y;private Random random;public Food() {random = new Random();newPosition();}public void newPosition() {// 随机生成食物位置x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;}public int getX() { return x; }public int getY() { return y; }public boolean isEaten(Snake snake) {// 检查食物是否被蛇吃掉return snake.getX()[0] == x && snake.getY()[0] == y;}
}

如何运行游戏

  1. 将上面的代码复制到四个Java文件中:SnakeGame.java, GamePanel.java, Snake.java, 和 Food.java
  2. 确保所有文件在同一个目录下
  3. 使用Java编译器编译这些文件:javac SnakeGame.java
  4. 运行编译后的程序:java SnakeGame

游戏操作说明

  • 使用方向键(上、下、左、右)控制蛇的移动方向
  • 吃到红色的食物会增加分数并让蛇变长
  • 如果蛇撞到边界或自己的身体,游戏结束
  • 游戏结束后按空格键可以重新开始

游戏改进建议

  1. 添加难度级别:随着分数增加,蛇的移动速度加快
  2. 添加不同类型的食物:有些食物提供额外分数,有些食物让蛇加速或减速
  3. 添加音效:吃到食物、游戏结束等事件添加音效
  4. 实现高分榜:记录最高分并显示在游戏界面

希望这篇文章能帮助你理解如何使用Java制作一个简单的贪吃蛇游戏!如果你有任何问题或建议,欢迎留言讨论。

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

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

相关文章

【linux】umask权限掩码

umask这个接口在一些程序初始化的时候经常会见到&#xff0c;处于安全性&#xff0c;可以缩小进程落盘文件的权限。 1、linux文件系统的权限规则 文件的默认权限由系统决定&#xff08;通常是 0666&#xff0c;即所有人可读可写&#xff09;。 目录的默认权限通常是 0777&am…

esp32cmini SK6812 2个方式

1 #include <SPI.h> // ESP32-C系列的SPI引脚 #define MOSI_PIN 7 // ESP32-C3/C6的SPI MOSI引脚 #define NUM_LEDS 30 // LED灯带实际LED数量 - 确保与实际数量匹配&#xff01; #define SPI_CLOCK 10000000 // SPI时钟频率 // 颜色结构体 st…

互联网大厂Java求职面试:Spring Cloud微服务架构设计中的挑战与解决方案

互联网大厂Java求职面试&#xff1a;Spring Cloud微服务架构设计中的挑战与解决方案 面试场景设定 郑薪苦是一位拥有丰富实战经验的Java开发者&#xff0c;他正在参加一场由某知名互联网大厂的技术总监主持的面试。这场面试将围绕Spring Cloud微服务架构展开&#xff0c;涵盖…

品鉴JS的魅力之防抖与节流【JS】

前言 小水一波&#xff0c;函数的防抖与节流。 文章目录 前言介绍实现方式防抖节流 介绍 防抖与节流的优化逻辑&#xff0c;在我们的日常开发中&#xff0c;有着一定的地位。 防抖和节流是两种常用的性能优化技术&#xff0c;用于限制某个函数在一定时间内被触发的次数,减少不…

# 使用 Hugging Face Transformers 和 PyTorch 实现信息抽取

使用 Hugging Face Transformers 和 PyTorch 实现信息抽取 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;信息抽取是一种常见的任务&#xff0c;其目标是从文本中提取特定类型的结构化信息。本文将介绍如何使用 Hugging Face Transformers 和 PyTorch 实现基于大…

Firecrawl MCP Server 深度使用指南

无论是市场分析师洞察行业动态、研究者收集学术资料&#xff0c;还是开发者为智能应用采集数据&#xff0c;都对网络数据采集工具提出了极高的要求。Firecrawl MCP Server 应运而生&#xff0c;它宛如一把犀利的 “数字手术刀”&#xff0c;能够精准地剖析网页&#xff0c;为用…

OceanBase数据库全面指南(基础入门篇)

文章目录 一、OceanBase 简介与安装配置指南1.1 OceanBase 核心特点1.2 架构解析1.3 安装部署实战1.3.1 硬件要求1.3.2 安装步骤详解1.3.3 配置验证二、OceanBase 基础 SQL 语法入门2.1 数据查询(SELECT)2.1.1 基础查询语法2.1.2 实际案例演示2.2 数据操作(INSERT/UPDATE/DE…

几种环境下的Postgres数据库安装

1. Postgres 数据库介绍 PostgreSQL&#xff08;又称 Postgres&#xff09;是一种强大、开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它具备高度的可靠性、稳定性和可扩展性&#xff0c;主要特点如下&#xff1a; 开源&#xff1a;PostgreSQL 是基于开…

函数[x]和{x}在数论中的应用

函数[x]和{x}在数论中的应用 函数[x]和{x}的定义与基本性质&#xff08;定义1&#xff0c;命题1&#xff09;定义1例1命题1 函数[x]和{x}的应用&#xff08;定理1&#xff0c;推论1-推论3&#xff09;例2定理1注解5推论1例3例4推论2推论3命题2 函数[x]和{x}的定义与基本性质&am…

Python爬虫(32)Python爬虫高阶:动态页面处理与Scrapy+Selenium+BeautifulSoup分布式架构深度解析实战

目录 引言一、动态页面爬取的技术背景1.1 动态页面的核心特征1.2 传统爬虫的局限性 二、技术选型与架构设计2.1 核心组件分析2.2 架构设计思路1. 分层处理2. 数据流 三、代码实现与关键技术3.1 Selenium与Scrapy的中间件集成3.2 BeautifulSoup与Scrapy Item的整合3.3 分布式爬取…

FreeSWITCH rtcp-mux 测试

rtcp 跟 rtp 占用同一个端口&#xff0c;这就是 rtcp 复用 Fs 呼出是这样的&#xff1a; originate [rtcp_muxtrue][rtcp_audio_interval_msec5000]user/1001 &echo 需要同时指定 rtcp_audio_interval_msec&#xff0c;否则 rtcp_mux 不能生效 Fs 呼入不需要配置&#xf…

day019-特殊符号、正则表达式与三剑客

文章目录 1. 磁盘空间不足-排查流程2. 李导推荐书籍2.1 大话存储2.2 性能之巅 3. 特殊符号3.1 引号系列&#xff08;面试题&#xff09;3.2 重定向符号3.2.1 cat与重定向3.2.2 tr命令&#xff1a;替换字符3.2.3 xargs&#xff1a;参数转换3.2.4 标准全量追加重定向 4. 正则表达…

Vue3 watch 使用与注意事项

watch 的第一个参数可以是不同形式的“数据源”&#xff1a;它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组&#xff1a; 1&#xff1a;reactive监听对象 <template><div><h1>情况二&#xff1a;watchEffect…

医学写作供应商管理全流程优化

1. 供应商筛选与评估 1.1 资质审核 1.1.1 行业认证核查 核查供应商的行业认证,如AMWA医学写作认证、EMWA会员资格、ISO 9001等,确保其专业资质。 1.1.2 团队背景评估 评估团队成员专业背景,包括医学/药学学位、临床试验经验、发表记录,保障专业能力。 1.1.3 国际规范熟悉…

固态硬盘颗粒类型、选型与应用场景深度解析

一、固态硬盘颗粒类型的技术演进与特性 固态硬盘&#xff08;SSD&#xff09;的性能核心在于存储单元结构的设计&#xff0c;这种设计直接决定了数据的存储密度、读写速度、耐久度及成本效益。当前主流的闪存颗粒类型呈现从单层到多层架构的梯度演进&#xff0c;其技术特征与应…

CAPL自动化-诊断Demo工程

文章目录 前言一、诊断控制面板二、诊断定义三、发送诊断通过类.方法的方式req.SetParameterdiagSetParameter四、SendRequestAndWaitForResponse前言 本文将介绍CANoe的诊断自动化测试,工程可以从CANoe的 Sample Configruration 界面打开,也可以参考下面的路径中打开(以实…

嵌入式预处理链接脚本lds和map文件

在嵌入式开发中&#xff0c;.lds.S 文件是一个 预处理后的链接脚本&#xff08;Linker Script&#xff09;&#xff0c;它结合了 C 预处理器&#xff08;Preprocessor&#xff09; 的功能和链接脚本的语法。它的核心作用仍然是 定义内存布局和链接规则&#xff0c;但通过预处理…

PT5F2307触摸A/D型8-Bit MCU

1. 产品概述 ● PT5F2307是一款51内核的触控A/D型8位MCU&#xff0c;内置16K*8bit FLASH、内部256*8bit SRAM、外部512*8bit SRAM、触控检测、12位高精度ADC、RTC、PWM等功能&#xff0c;抗干扰能力强&#xff0c;适用于滑条遥控器、智能门锁、消费类电子产品等电子应用领域。 …

RabbitMQ——消息确认

一、消息确认机制 生产者发送的消息&#xff0c;可能有以下两种情况&#xff1a; 1> 消息消费成功 2> 消息消费失败 为了保证消息可靠的到达消费者&#xff08;&#xff01;&#xff01;&#xff01;注意&#xff1a;消息确认机制和前面的工作模式中的publisher confi…

C++异步(1)

什么是异步? 异步就是多个线程是同时执行的&#xff0c;与之相对的就是线程同步&#xff0c;二者都应用在并发的场景上。 异步的特点 异步执行的任务无需等待其他任务完成&#xff0c;其本身是通过非阻塞的方式执行的&#xff0c;不依赖前驱任务&#xff0c;通常用于IO密集…