当前位置: 首页 > news >正文

2024全国大学生电子设计大赛全国初赛 E题 三子棋游戏装置 一等奖满分最简方案

感想:电赛初赛控制类题还是蛮简单的,别被五花八门的硬件搞懵了(决赛当我没说)。抓住核心,理念都是通用的。我是计科专业的,因此选择的控制类E题,相对来说背的知识要少很多,更考验智商。其实电赛结果都不重要,在电赛经历中对自己的磨练,尤其是“所想即所得”的快感弥足珍贵。要不是参加电赛,我都不敢想象自己做了一个人机对弈装置。通过电赛,见到了更宽广的世界。

声明:本文中绝大部分算法(所有核心算法)均是我个人想出来的,部分细节由队友补充,转载请私信!严禁盗代码!如果我发现谁盗我代码我直接全网曝光并且停更!

前言:我本人一向以天才自居,算法也都是最简洁干练的(那些艰深晦涩而复杂的算法往往是愚蠢的人写出),很多人劝我不要把代码开源,我偏要,我看不惯CSDN的那些VIP专栏,那是把智慧锁进了笼子里。文章格式就懒得调了。如果你们发现本文在逻辑上有缺失的部分,欢迎私信我进行补充!

正文

    • 声明:本文中绝大部分算法(所有核心算法)均是我个人想出来的,部分细节由队友补充,转载请私信!严禁盗代码!如果我发现谁盗我代码我直接全网曝光并且停更!
  • 三个核心算法:
    • 1.棋子识别。
    • 2.棋盘方格匹配按键标签。
    • 3.对弈算法。
  • 其他:懒得写了。
  • 总结:懒得总结了,可以发现,如果优化得当,做电赛E题只需要几百行代码即可获得满分,如果你写了几千行代码,说明你智商有限,还是转行搞其他题目吧,谢谢!如果我的智商故意冒犯了你,请举报一下,就说我太聪明了,不谢!

三个核心算法:

1.棋子识别。

通过识别棋盘方格,计算差分列表,得出棋盘状态变化情况,根据黑棋先行的规则确定棋谱并保存。由于扰动的存在,实际每帧中方格的位置都会变化,因此通过计算汉明距离来匹配方格(待匹配方格与base(全局静态变量,初始九宫格)中九个方格进行比较)。理想情况汉明距离为一个方格,我取一半(当然也可以取1/3)。

// 计算两个点之间的距离
double distance(position p1, position p2)
{return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}// 寻找A中满足条件的点,并返回满足条件的点的个数
int find_points(position A[], int sizeA, position B[], int sizeB, position result[])
{int i, j;double threshold;int result_count = 0;threshold = g_min_distance;// 遍历A中的点,判断是否满足条件for (i = 0; i < sizeA; ++i){int satisfies = 1;for (j = 0; j < sizeB; ++j){if (distance(A[i], B[j]) <= threshold){satisfies = 0;}}if (satisfies){result[result_count++] = A[i];}}return result_count;
}double hamming(void)
{ // 计算汉明距离double min_distance = 99999;int i, j;g_min_distance = 99999;for (i = 0; i < 9; ++i){for (j = i + 1; j < 9; ++j){double d = distance(g_base[i], g_base[j]);if (d < min_distance){min_distance = d;}}}g_min_distance = min_distance / 2;return min_distance;
}position bind(u8 key)
{return g_base[key - 1];
}u8 label_1(position pos)
{int i;position tem;for (i = 1; i < 10; i++){tem = bind(i);if (distance(pos, tem) < g_min_distance){return i;}}return 0;
}position findpawns(position *fields, u8 lens)
{int result_count;int i;int j;int k;int h;position result[MAX_POINTS];position result2[MAX_POINTS];u8 disp[9] = {0};u8 comp[9] = {0};u8 compcnt = 0;static position PreResult[MAX_POINTS];static u8 PreResultCnt = 0;u8 key1;u8 key2;u8 sat;position a;if (lens == prefield_len) // 悔棋判定{for (j = 0; j < lens; j++){disp[j] = label_1(fields[j]);}for (k = 1; k < 10; k++){	sat = 1;for (h = 0; h < g_u8BordCnt; h++){		if (k == g_u8Bord[h]){sat = 0;}}if (sat==1){comp[compcnt] = k;compcnt++;}}for (j = 0; j < lens; j++){sat = 1;for (k = 0; k < lens; k++){if (disp[j] == comp[k]){sat = 0;}}if (sat == 1){key1=disp[j];}}for (j = 0; j < lens; j++){sat = 1;for (k = 0; k < lens; k++){if (comp[j] == disp[k]){sat = 0;}}if (sat == 1){key2=comp[j];}}//move(key2,key1) 此处代码省略a.x = 0;a.y = 0;return a;}prefield_len = lens;result_count = find_points(g_base, 9, fields, lens, result);if (PreResultCnt != 0){find_points(result, result_count, PreResult, PreResultCnt, result2);}for (i = 0; i < result_count; i++){PreResult[i].x = result[i].x;PreResult[i].y = result[i].y;}if (PreResultCnt != 0){PreResultCnt = result_count;return result2[0];}else{PreResultCnt = result_count;return result[0];}
}u8 SetLog(position *fields, u8 fieldlens)
{ // 记录棋谱position tem =findpawns(fields, fieldlens);if (tem.x!=0&&tem.y!=0){g_u8Bord[g_u8BordCnt] = label_1(tem);g_u8BordCnt++;return 1;}return 0;}u8 FillFileds(void)
{position fileds[MAX_POINTS];u8 u8FiledLen = 0;int i;for (i = 0; i < MAX_POINTS; i++){if (g_PointPosition[i].x != 0 && g_PointPosition[i].y != 0){u8FiledLen++;fileds[i].x = g_PointPosition[i].x;fileds[i].y = g_PointPosition[i].y;}else{fileds[i].x = 0;fileds[i].y = 0;}}return SetLog(fileds, u8FiledLen);
}

Q:为什么不直接识别棋子而要识别方格?
A:识别棋子方案复杂,且OpenMV无库函数支持(只有下限阈值)。
Q:差分列表是什么意思?
A:首先识别空白方格列表(棋子所在方格低于find_blob阈值),第一次与base作差求出棋子所占空格列表(数组),与pre作差求出当前走法。

2.棋盘方格匹配按键标签。

由于实际中无法做到完全棋盘正置,故不需要区分是否旋转(不旋转默认为右转)。对于当前棋盘,利用一个布尔变量区分左转或者右转,用九个点(用(x,y)坐标形式表示一点)组成的一维数组表示各方格位置。对于右转的情况,先取y坐标最小的点,作为该组中的直线基准,然后取y坐标次小的(要求该点与本组基准点构成的直线斜率正负符号为b,如果斜率无法计算即直线垂直不符合要求),然后取y坐标次次小的(要求该点与本组基准点构成的直线斜率正负符号为b,如果斜率无法计算即直线垂直不符合要求),此三点为一组,分别标号1、2、3,对于剩下的点继续该操作分组,组内各点标号递增,如第二组内三点标号分别为4、5、6.最后按照标号大小顺序依次输出对应的点坐标。左转类似。这样可以保证坐标系和棋盘相对位置在旋转后不变,方格的顺序也不发生改变。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>typedef struct
{double x;double y;
} position;typedef struct
{int x;int y;int label;
} Point;position g_base[MAX_POINTS];
bool rt = 0;
// 比较函数,用于qsort按y坐标排序
int compare(const void *a, const void *b)
{Point *pointA = (Point *)a;Point *pointB = (Point *)b;if (pointA->y != pointB->y){return pointA->y - pointB->y;}else{if (rt == 0) // 1return pointA->x - pointB->x;elsereturn pointB->x - pointA->x;}
}// 判断两点间的斜率符号是否与布尔变量b相符
bool isValidSlope(Point base, Point next, bool b)
{int dx = next.x - base.x;int dy = next.y - base.y;bool slopeSign;if (dx == 0){return false; // 垂直线不符合要求}slopeSign = (dy > 0) == (dx > 0);return slopeSign == b;
}void groupPoints(Point *points, int size)
{int label = 1;int i;qsort(points, size, sizeof(Point), compare);for (i = 0; i < size; i++){int count = 1; // 找俩点Point base = points[i];int n;if (points[i].label != 0){continue;}// 选择基准点points[i].label = label++;for (n = 0; n < size && count < 3; n++){if (points[n].label == 0){if (isValidSlope(base, points[n], rt)){points[n].label = label++;count++;}}}}
}void SortPoint()
{int i, j;j = 1;for (i = 0; i < 9;){if (g_PointPosition[i].label == j){g_base[j - 1].x = g_PointPosition[i].x;g_base[j - 1].y = g_PointPosition[i].y;j++;if (j > 9){break;}else{i = 0;continue;}}else{i++;}}hamming();
}void Label(bool b)
{rt = b;groupPoints(g_PointPosition, 9);SortPoint();
}

3.对弈算法。

基本核心算法:启发式,计算有效直线(指有经过三个方格中心的直线且其上没有对方落子)的组数(按子数排序),返回最大着法。
补丁(按优先级排序):

  1. 己方三点必胜
  2. 对方二点必堵
  3. 己方双重威胁
  4. 对方双重威胁

注意:以下代码为电赛现敲,未经过优化,可复用部分一大把(当时图方便直接复制粘贴的),我懒得改了。

// 根据当前棋谱生成棋盘
void generate_board(int board[9], int moves[], int move_count)
{int i;for (i = 0; i < 9; i++){board[i] = EMPTY;}for (i = 0; i < move_count; i++){board[moves[i] - 1] = (i % 2 == 0) ? BLACK : WHITE;}
}// 判断是否有赢家
int check_winner(int board[9])
{int i;int win_positions[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, // 行{0, 3, 6},{1, 4, 7},{2, 5, 8}, // 列{0, 4, 8},{2, 4, 6} // 对角线};for (i = 0; i < 8; i++){int a = win_positions[i][0];int b = win_positions[i][1];int c = win_positions[i][2];if (board[a] == board[b] && board[b] == board[c] && board[a] != EMPTY){return board[a];}}return EMPTY;
}// 计算在给定位置下棋后的最长同线长度和组数
void evaluate_position(int board[9], int player, int pos, int *max_length, int *num_groups)
{int i;int j;int lines[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, // 行{0, 3, 6},{1, 4, 7},{2, 5, 8}, // 列{0, 4, 8},{2, 4, 6} // 对角线};*max_length = 0;*num_groups = 0;for (i = 0; i < 8; i++){int length = 0;int valid_group = 1;for (j = 0; j < 3; j++){int index = lines[i][j];if (index == pos || board[index] == player){length++;}else if (board[index] != EMPTY){valid_group = 0;break;}}if (valid_group){if (length > *max_length){*max_length = length;*num_groups = 1;}else if (length == *max_length){(*num_groups)++;}}}
}// 检查是否有获胜的走法
int find_winning_move(int board[9], int player)
{int i;int j;int lines[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, // 行{0, 3, 6},{1, 4, 7},{2, 5, 8}, // 列{0, 4, 8},{2, 4, 6} // 对角线};for (i = 0; i < 8; i++){int count = 0;int empty_pos = -1;for (j = 0; j < 3; j++){int index = lines[i][j];if (board[index] == player){count++;}else if (board[index] == EMPTY){empty_pos = index;}else{count = 0;break;}}if (count == 2 && empty_pos != -1){return empty_pos;}}return -1;
}// 检查是否有阻止对方获胜的走法
int find_blocking_move(int board[9], int player)
{int opponent = (player == BLACK) ? WHITE : BLACK;return find_winning_move(board, opponent);
}// 检查是否存在某个位置,如果让对方在该位置下子,会使对方在两个有效直线上都有两个子的情况
int find_double_threat_move(int board[9], int player)
{int i;int j;int k;int opponent = (player == BLACK) ? WHITE : BLACK;int lines[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, // 行{0, 3, 6},{1, 4, 7},{2, 5, 8}, // 列{0, 4, 8},{2, 4, 6} // 对角线};for (i = 0; i < 9; i++){if (board[i] == EMPTY){int threat_count = 0;for (j = 0; j < 8; j++){int count = 0;int empty_count = 0;for (k = 0; k < 3; k++){int index = lines[j][k];if (board[index] == opponent || index == i){count++;}else if (board[index] == EMPTY){empty_count++;}}if (count == 2 && empty_count == 1){threat_count++;}if (threat_count >= 2){return i;}}}}return -1;
}// 主策略函数
void next_move_strategy(int moves[], int move_count, int result[])
{int i;int board[9];int move;int winner;int current_player;generate_board(board, moves, move_count);// 检查当前棋局是否已经有赢家winner = check_winner(board);if (winner != EMPTY){for (i = 0; i < move_count; i++){result[i] = moves[i];}MyWin = winner;return;}current_player = (move_count % 2 == 0) ? BLACK : WHITE;// 检查是否有获胜的走法move = find_winning_move(board, current_player);if (move == -1){// 检查是否有阻止对方获胜的走法move = find_blocking_move(board, current_player);}if (move == -1){// 检查是否有使己方形成双重威胁的走法int op;op = (move_count % 2 == 0) ? WHITE : BLACK;move = find_double_threat_move(board, op);}if (move == -1){// 检查是否有使对方形成双重威胁的走法move = find_double_threat_move(board, current_player);}if (move == -1){// 否则,选择最佳的一般走法int best_move = -1;int best_length = -1;int best_num_groups = -1;for (i = 0; i < 9; i++){if (board[i] == EMPTY){int max_length, num_groups;evaluate_position(board, current_player, i, &max_length, &num_groups);if (max_length > best_length || (max_length == best_length && num_groups > best_num_groups)){best_length = max_length;best_num_groups = num_groups;best_move = i;}}}move = best_move;}// 生成新的棋谱for (i = 0; i < move_count; i++){result[i] = moves[i];}result[move_count] = move + 1; // 位置从1到9
}

其他:懒得写了。

总结:懒得总结了,可以发现,如果优化得当,做电赛E题只需要几百行代码即可获得满分,如果你写了几千行代码,说明你智商有限,还是转行搞其他题目吧,谢谢!如果我的智商故意冒犯了你,请举报一下,就说我太聪明了,不谢!

相关文章:

2024全国大学生电子设计大赛全国初赛 E题 三子棋游戏装置 一等奖满分最简方案

感想&#xff1a;电赛初赛控制类题还是蛮简单的&#xff0c;别被五花八门的硬件搞懵了&#xff08;决赛当我没说&#xff09;。抓住核心&#xff0c;理念都是通用的。我是计科专业的&#xff0c;因此选择的控制类E题&#xff0c;相对来说背的知识要少很多&#xff0c;更考验智商…...

尚品汇-ES(三十一)

目录&#xff1a; &#xff08;1&#xff09;封装搜索相关实体对象 &#xff08;2&#xff09;搜索接口封装 &#xff08;3&#xff09;在service-list-client模块添加远程接口 &#xff08;1&#xff09;封装搜索相关实体对象 搜索参数实体&#xff1a;SearchParam 搜索参…...

NC 跳台阶

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 一只青蛙一次…...

linux 文件编程

1. 标准IO 也称为标准输入输出&#xff08;Standard Input/Output&#xff09;&#xff0c;是计算机编程中一种常见的IO操作方式&#xff0c;特别是在C语言及其衍生语言中广泛使用。它主要通过标准C库中的函数来实现&#xff0c;提供了丰富的接口用于数据的输入和输出。 文本文…...

【后端速成 Vue】实现动态表白墙

前言&#xff1a; 通过前面几篇的文章的讲解&#xff0c;已经学习到了很多的 Vue 指令了&#xff0c;那么现在就将学习到的指令利用起来&#xff0c;做一个小的 demo。 最终效果图&#xff1a; 通过效果图可以发现&#xff0c;一共有这几个功能&#xff1a; ● 渲染列表&…...

【日常开发】 java返回ECharts数据结构封装

java返回ECharts数据结构封装 一、前端页面示例图如下&#xff1a; 二、准备测试数据&#xff1a; 三、后端 格式封装代码&#xff1a; 四、最终结果&#xff1a; &#x1f388;边走、边悟&#x1f388;迟早会好 一、前端页面示例图如下&#xff1a; 二、准备测试数据&am…...

Table表格控件实现单选功能

Table表格控件实现单选功能 <el-tableref"tableRef"height"385"style"--el-table-border-color: none"row-key"contractId"highlight-current-rowsingle-selectselect"handleSelect":data"contractInfo">&l…...

AI技术加速落地 港科广联手思谋打开智能缺陷检测新纪元

AI 技术应用落地的元年&#xff0c;工业是主战场&#xff0c;尤其是工业缺陷检测。 在“生产制造-缺陷检测-工艺优化-生产制造”的智能制造闭环链条中&#xff0c;基于AI的智能缺陷检测扮演着“把关者”的角色。但这个把关者长期以来却缺少一个称手的工具——样本量大、精度高…...

Python爬虫开发:BeautifulSoup、Scrapy入门

在现代网络开发中&#xff0c;网络爬虫是一个非常重要的工具。它可以自动化地从网页中提取数据&#xff0c;并且可以用于各种用途&#xff0c;如数据收集、信息聚合和内容监控等。在Python中&#xff0c;有多个库可以用于爬虫开发&#xff0c;其中BeautifulSoup和Scrapy是两个非…...

数据科学、数据分析、人工智能必备知识汇总-----常用数据分析方法-----持续更新

数据科学、数据分析、人工智能必备知识汇总-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/140174015 文章目录 一、对比分析法1. 按时间和地区2. 同比和环比 二、分组分析法三、结构分析法四、交叉分析法五、矩阵分…...

学习vue Router 一 起步,编程式导航,历史记录,路由传参

目录 起步&#xff0c;安装 1. 安装 2. 使用 命名路由 编程式导航 1. 字符串模式 2. 对象模式 3. 命名路由模式 历史记录 replace的使用 横跨历史 路由传参 1. query路由传参 2. 动态路由传参 3. 二者的区别 起步&#xff0c;安装 router 路由 因为vue是单页应用…...

Qt/C++最新地图组件发布/历时半年重构/同时支持各种地图内核/包括百度高德腾讯天地图

一、前言说明 最近花了半年时间&#xff0c;专门重构了整个地图组件&#xff0c;之前写的比较粗糙&#xff0c;有点为了完成功能而做的&#xff0c;没有考虑太多拓展性和易用性。这套地图自检这几年大量的实际项目和用户使用下来&#xff0c;反馈了不少很好的建议和意见&#…...

Laravel + Thinkphp 生成二维码

安装依赖 composer require endroid/qr-code 编写ThinkPhP代码 public function index() {// 创建二维码内容$qrCode new QrCode(Hello World);// 设置二维码的配置$qrCode->setSize(300);$qrCode->setMargin(10);// 获取二维码图像$writer new PngWriter();$result…...

2408C++,C++20的无侵入式反射

原文 C17基于结构绑定的编译期反射 事实上不需要宏的编译期反射在C17中已用得很多了,比如struct_pack的编译期反射就不需要宏,因为C17结构绑定可直接得到一个聚集类的成员的引用. struct person {int id;std::string name;int age; }; int main() {person p{1, "tom&qu…...

抽象工厂模式(Abstract factory pattern)- python实现

抽象工厂模式的通俗示例 想象一下&#xff0c;你正在经营一家家具店&#xff0c;你需要从不同的供应商那里采购不同的家具系列。有的供应商提供的是现代风格家具&#xff0c;包括现代沙发、现代椅子和现代桌子&#xff1b;而有的供应商提供的是古典风格家具&#xff0c;包括古…...

adb Connection reset by peer的解决方法

本文同步发于&#xff1a;https://www.cnblogs.com/yeshen-org/p/18350232 最近在编译一个老项目&#xff0c;项目中依赖了很多第三方库&#xff0c;用gradle编译要20-30分钟&#xff0c;而且内存开销很大。 公司配的15G内存的电脑&#xff0c;一次编译能用到14G。 编译的时候&…...

111111111

1111111111111111111...

搜维尔科技:Varjo XR-4使用UE5 打造最具沉浸感的混合现实环境

Varjo XR-4使用UE5打造最具沉浸感的混合现实环境 搜维尔科技&#xff1a;Varjo XR-4使用UE5 打造最具沉浸感的混合现实环境...

从分散到集中:TSINGSEE青犀EasyCVR视频汇聚网关在视频整体监控解决方案中的整合作用

边缘计算视频汇聚网关是基于开放式、大融合、全兼容、标准化的设计架构理念&#xff0c;依据《安全防范视频监控联网系统信息传输、交换、控制技术要求》&#xff08;GB/T28181-2011&#xff09;标准开发&#xff0c;集流媒体转发、视频编码、视频管理、标准通信协议、网络穿透…...

React学习-jsx语法

jsx语法&#xff0c;浏览器不认识&#xff0c;需要经过babel编译 https://babeljs.io/ 面试题&#xff1a;jsx的作用&#xff1f; 普通回答&#xff1a;可以在js中返回dom&#xff0c;经过babel编译成js认识的代码import { jsx as _jsx, jsxs as _jsxs } from "react/j…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...