JVM——Java字节码基础
引入
Java字节码(Java Bytecode)是Java技术体系的核心枢纽,所有Java源码经过编译器处理后,最终都会转化为.class
文件中的字节码指令。这些指令不依赖于具体的硬件架构和操作系统,而是由Java虚拟机(JVM)统一解释执行,从而实现了“一次编写,到处运行”的能力。
Java字节码核心概览:栈架构与指令设计
字节码的本质:平台无关的中间语言
Java字节码是一种二进制形式的指令集,每个指令由操作码(Opcode,1字节,0-255)和可选的操作数(Operands)组成:
-
操作码:唯一标识指令功能,例如
0x03
代表iconst_0
(压入整数0),0xB6
代表invokevirtual
(调用虚方法)。 -
操作数:提供指令所需的参数,可能是常量池索引、局部变量索引等。例如
ldc #18
中的#18
表示常量池第18项。
基于栈的计算模型:JVM的执行基石
与C/C++依赖硬件寄存器的编译模型不同,Java字节码基于栈架构,其核心数据结构是每个栈帧中的操作数栈和局部变量区:
-
操作数栈:用于暂存计算过程中的操作数和结果,遵循“先进后出”原则,所有运算(如加减乘除)均通过栈操作完成。
-
局部变量区:以数组形式存储方法参数、
this
指针(实例方法)和局部变量,通过索引快速访问(如iload_1
加载索引1的int
变量)。
栈架构 vs 寄存器架构:
特性 | 栈架构(Java字节码) | 寄存器架构(如x86汇编) |
---|---|---|
可移植性 | 强(不依赖硬件寄存器) | 弱(依赖具体平台寄存器布局) |
指令长度 | 短(操作码固定1字节) | 长(需指定寄存器编号) |
执行效率 | 较低(频繁入栈/出栈开销) | 较高(直接操作寄存器) |
编译复杂度 | 简单(无需寄存器分配) | 复杂(需处理寄存器冲突) |
操作数栈:JVM的“运算引擎”
核心栈操作指令:数据处理与栈结构控制
操作数栈的指令可分为数据操作指令和栈结构操作指令,前者完成数据运算,后者调整栈的形态:
数据操作指令(算术、加载、存储)
指令分类 | 指令示例 | 功能描述 | 栈操作示例(栈顶→栈底) |
---|---|---|---|
常量加载 | iconst_5 | 将整数5压入栈 | 压入前:[A] → 压入后:[5, A] |
ldc "hello" | 从常量池加载字符串"hello"压入栈 | 压入前:[B] → 压入后:["hello", B] | |
变量加载 | iload_2 | 从局部变量区索引2加载int 值压入栈 | 假设变量值为10,栈变为[10, C] |
算术运算 | iadd | 弹出栈顶两个int 值相加,结果压栈 | 压入前:[3, 2] → 压入后:[5] |
dsub | 弹出栈顶两个double 值相减,结果压栈(占2个栈单元) | 压入前:[y, x] → 压入后:[x-y] | |
类型转换 | i2b | 弹出栈顶int 值,转换为byte 后压栈(截断高位) | 压入前:[200] → 压入后:[-56] |
栈结构操作指令(复制、弹出、交换)
指令示例 | 功能描述 | 栈变化示例(栈顶→栈底) |
---|---|---|
dup | 复制栈顶1个元素,压入栈顶 | 原栈:[A, B] → 新栈:[A, A, B] |
dup2 | 复制栈顶2个元素(用于long /double ),压入栈顶 | 原栈:[X, Y](long类型) → 新栈:[X, Y, X, Y] |
pop | 弹出栈顶1个元素 | 原栈:[A, B] → 新栈:[B] |
pop2 | 弹出栈顶2个元素(处理long /double ) | 原栈:[X, Y](double) → 新栈:[] |
swap | 交换栈顶两个元素的位置 | 原栈:[1, 2] → 新栈:[2, 1] |
关键场景:
-
对象构造:
new Object()
后需用dup
复制未初始化引用,以便同时调用构造器和保留引用(见文档示例)。 -
结果舍弃:调用
void
方法后用pop
丢弃返回值(如System.out.println()
无需返回值)。
栈深度优化:编译期确定与运行时风险
每个方法的操作数栈最大深度在编译时由javac
计算,并写入.class
文件的Code
属性(如stack=2
)。若运行时栈深度超过声明值,将抛出StackOverflowError
。 优化策略:
-
避免冗余压栈:复用栈顶临时结果,减少
dup
/pop
操作。 -
限制递归深度:对深度递归方法(如斐波那契递归),改用循环或尾递归优化。
示例分析:加法运算的栈操作全过程
public void addDemo() {int a = 10 + 20;
}
对应字节码及栈变化:
0: bipush 10 // 压入10 → 栈:[10]
2: bipush 20 // 压入20 → 栈:[20, 10]
4: iadd // 弹出20和10,相加后压入30 → 栈:[30]
5: istore_1 // 弹出30,存入局部变量1 → 栈:[]
6: return
常数加载指令表:从常量池到栈的高效传输
常数加载指令用于将字面量或常量池数据快速压入操作数栈,根据数据类型和范围分为三大类,下表为完整分类:
基础类型常量加载指令(const
系列)
数据类型 | 指令 | 支持值范围 | 操作码 | 示例 | 说明 |
---|---|---|---|---|---|
int | iconst_m1 | -1 | 0x02 | iconst_m1 → 压入-1 | 仅支持-1~5,共7个特定值 |
iconst_0 -iconst_5 | 0~5 | 0x03 -0x08 | iconst_3 → 压入3 | 操作码紧凑,无需操作数 | |
long | lconst_0 | 0L | 0x09 | lconst_0 → 压入0L | 仅支持0L和1L,占2个栈单元 |
lconst_1 | 1L | 0x0A | lconst_1 → 压入1L | ||
float | fconst_0 | 0.0f | 0x0B | fconst_0 → 压入0.0f | 仅支持0.0f、1.0f、2.0f |
fconst_1 | 1.0f | 0x0C | fconst_1 → 压入1.0f | ||
fconst_2 | 2.0f | 0x0D | fconst_2 → 压入2.0f | ||
double | dconst_0 | 0.0d | 0x0E | dconst_0 → 压入0.0d | 仅支持0.0d和1.0d,占2个栈单元 |
dconst_1 | 1.0d | 0x0F | dconst_1 → 压入1.0d | ||
引用类型 | aconst_null | null 引用 | 0x01 | aconst_null → 压入null | 唯一直接加载引用的非常量指令 |
中等范围整数加载指令(push
系列)
指令 | 数据类型 | 支持值范围 | 操作数长度 | 示例 | 说明 |
---|---|---|---|---|---|
bipush | int | -128~127(1字节) | 1字节 | bipush 100 → 压入100 | 用于单字节表示的整数 |
sipush | int | -32768~32767(2字节) | 2字节 | sipush 10000 → 压入10000 | 用于双字节表示的整数 |
通用常量加载指令(ldc
系列)
指令 | 数据类型 | 功能描述 | 操作数 | 示例 | 说明 |
---|---|---|---|---|---|
ldc | int /float /String /Class | 加载常量池中的对应类型常量 | 1字节索引 | ldc #18 → 加载常量池第18项 | 最灵活的常量加载方式 |
ldc_w | 同上 | 支持更大范围的常量池索引(2字节) | 2字节索引 | ldc_w #256 → 加载第256项 | 用于常量池索引超过255的场景 |
ldc2_w | long /double | 加载长整型或双精度浮点常量 | 2字节索引 | ldc2_w #300 → 加载long值 | 处理占2个栈单元的常量 |
应用场景总结:
-
小整数:优先使用
iconst
(如05)或`bipush`(如-128127)。 -
大范围数值/字符串/类引用:使用
ldc
系列,通过常量池间接加载。 -
极致性能:避免频繁调用
ldc
,将常用常量缓存到局部变量区。
局部变量区:数据存储的“高速缓存”
局部变量表结构:槽位分配与复用机制
局部变量区是一个变量槽(Slot)数组,每个槽存储一个基本类型值(除long
/double
占2个槽)或引用:
-
实例方法:索引0固定为
this
指针,后续索引依次为方法参数(如public void foo(int a, long b)
中,a
占索引1,b
占索引2和3)。 -
静态方法:无
this
指针,参数从索引0开始存储。 -
槽复用:当局部变量作用域不重叠时,编译器会复用同一槽位(如代码块内的
int i
和String s
共享同一槽),节省内存空间。
局部变量访问指令表:加载与存储的类型安全控制
访问指令严格区分数据类型,分为加载(Load)和存储(Store)两类,如下表所示:
数据类型 | 加载指令(局部变量→栈) | 存储指令(栈→局部变量) | 简化形式(索引0-3) | 说明 |
---|---|---|---|---|
int /boolean /byte /char /short | iload [n] | istore [n] | iload_0 -iload_3 | 加载时自动转型为int ,存储时截断 |
long | lload [n] | lstore [n] | lload_0 -lload_3 | 占用连续两个槽(n和n+1) |
float | fload [n] | fstore [n] | fload_0 -fload_3 | 单精度浮点,直接存储为4字节 |
double | dload [n] | dstore [n] | dload_0 -dload_3 | 双精度浮点,占用两个槽 |
引用类型 | aload [n] | astore [n] | aload_0 -aload_3 | 存储对象引用,支持多态类型校验 |
特殊指令:iinc
的局部变量原子自增
iinc M N
是唯一直接操作局部变量区的指令,功能是将索引M的int
变量增加N,常用于循环计数器:
for (int i = 0; i < 10; i++) {// 循环体
}
对应字节码:
0: iconst_0 // 压入0,存入i(索引1)
1: istore_1
2: goto 8 // 跳转到条件判断
5: iinc 1 1 // i自增1(M=1,N=1)
8: iload_1 // 加载i
9: bipush 10 // 压入10
11: iflt 5 // i < 10则跳转执行循环体
注意:iinc
仅适用于int
类型,对long
/double
无效;若变量为其他类型,需先转换为int
再操作。
示例分析:局部变量的加载与存储全过程
public void localVarDemo(String name, int age) {String info = name + " is " + age;int localVar = age + 10;
}
字节码关键指令:
0: aload_1 // 加载参数name(索引1)→ 栈:[name]
1: ldc " is " // 加载字符串" is " → 栈:[" is ", name]
3: invokevirtual String.concat() // 拼接 → 栈:[name+" is "]
4: iload_2 // 加载参数age(索引2)→ 栈:[age, name+" is "]
5: iadd // 此处应为字符串拼接,实际需invokevirtual,示例简化为数值运算
...
数组访问指令表:类型安全的底层实现
Java数组操作通过专用字节码指令实现,涵盖创建、元素访问和长度查询,以下是完整分类:
数组创建指令
指令 | 功能描述 | 操作数 | 示例 | 说明 |
---|---|---|---|---|
newarray T | 创建基本类型数组 | 1字节类型标识(如T=int ) | newarray int → 创建int数组 | T可选int 、byte 、char 等 |
anewarray C | 创建引用类型数组 | 2字节类名索引(常量池) | anewarray java/lang/String → 创建String数组 | 数组元素初始化为null |
multianewarray A N | 创建多维数组 | 类名索引A + 各维度长度N | multianewarray [[I 2 → 创建2维int数组 | N为维度参数,如{2, 3} 表示2×3数组 |
数组元素访问指令(按类型区分)
元素类型 | 加载指令(取元素→栈) | 存储指令(栈→元素) | 指令执行前栈状态(从顶到底) | 说明 |
---|---|---|---|---|
boolean /byte | baload | bastore | [arrayRef, index, value](存储时) | boolean 与byte 共用指令 |
char | caload | castore | [arrayRef, index](加载时) | 加载char 为16位无符号整数 |
short | saload | sastore | 存储时自动截断为16位 | |
int | iaload | iastore | 最常用的数组访问指令 | |
long | laload | lastore | [arrayRef, index](加载后栈顶为8字节long) | 占用2个栈单元 |
float | faload | fastore | 单精度浮点,4字节存储 | |
double | daload | dastore | 双精度浮点,占用2个栈单元 | |
引用类型 | aaload | aastore | [arrayRef, index, objRef](存储时) | 存储前检查objRef 是否为数组元素类型子类型 |
数组长度查询指令
指令:arraylength
功能:弹出栈顶数组引用,压入数组长度(int
类型)。
示例:
int len = arr.length;
// 字节码:
0: aload_1 // 加载数组引用(索引1)→ 栈:[arr]
1: arraylength // 压入长度 → 栈:[len]
2: istore_2 // 存入局部变量2
示例分析:数组操作的字节码全流程
public void arrayDemo() {int[] arr = new int[3];arr[0] = 10;int first = arr[0];
}
对应字节码:
0: iconst_3 // 压入数组长度3 → 栈:[3]
1: newarray int // 创建int数组 → 栈:[arrRef]
3: astore_1 // 存储数组引用到局部变量1 → 局部变量1=arrRef
4: aload_1 // 加载数组引用 → 栈:[arrRef]
5: iconst_0 // 压入索引0 → 栈:[0, arrRef]
6: bipush 10 // 压入值10 → 栈:[10, 0, arrRef]
8: iastore // 存储值到arr[0] → 栈:[]
9: aload_1 // 加载数组引用 → 栈:[arrRef]
10: iconst_0 // 压入索引0 → 栈:[0, arrRef]
11: iaload // 加载arr[0] → 栈:[10]
12: istore_2 // 存入局部变量2(first)
返回指令表:方法执行的最终出口
返回指令根据方法返回值类型分为7类,确保数据正确传递给调用者,下表为详细分类:
返回值类型 | 返回指令 | 功能描述 | 字节码示例 | 栈操作(执行前) | 说明 |
---|---|---|---|---|---|
void | return | 无返回值,结束方法执行 | return | 栈可为空或任意状态 | 用于void 方法或构造器 |
int | ireturn | 返回int 类型值 | ireturn | 栈顶为int 值 | 自动处理boolean /byte /char /short 的返回 |
long | lreturn | 返回long 类型值 | lreturn | 栈顶为long 值(占2个单元) | 弹出2个栈单元,返回64位长整型 |
float | freturn | 返回float 类型值 | freturn | 栈顶为float 值 | 按IEEE 754单精度格式返回 |
double | dreturn | 返回double 类型值 | dreturn | 栈顶为double 值(占2个单元) | 弹出2个栈单元,返回双精度值 |
引用类型 | areturn | 返回对象或数组引用 | areturn | 栈顶为引用值 | 需与方法声明的返回类型兼容 |
未声明返回 | return | 编译器自动插入(如void 方法结尾) | 无显式返回语句时 | 隐式执行return | 确保方法所有路径都有返回 |
异常处理:
-
若方法未显式返回(如
void
方法),编译器会自动添加return
指令。 -
若返回值类型不匹配(如
int
方法返回double
),编译期直接报错;运行时areturn
会检查引用类型兼容性(抛出ClassCastException
若不匹配)。
综合案例:从源码到字节码的完整映射
以文档中的经典示例bar
方法为例:
public static int bar(int i) {return ((i + 1) - 2) * 3 / 4;
}
字节码详细解析
Code:
stack=2, locals=1, args_size=1 // 操作数栈深度2,局部变量1个(参数i)
0: iload_0 // 加载局部变量0(i)→ 栈:[i]
1: iconst_1 // 压入1 → 栈:[1, i]
2: iadd // 相加,栈顶变为i+1 → 栈:[i+1]
3: iconst_2 // 压入2 → 栈:[2, i+1]
4: isub // 相减,栈顶变为i+1-2=i-1 → 栈:[i-1]
5: iconst_3 // 压入3 → 栈:[3, i-1]
6: imul // 相乘,栈顶变为(i-1)*3 → 栈:[(i-1)*3]
7: iconst_4 // 压入4 → 栈:[4, (i-1)*3]
8: idiv // 相除,栈顶变为(i-1)*3/4 → 栈:[result]
9: ireturn // 返回结果,方法结束
操作数栈变化图解
指令步骤 | 操作数栈状态(栈顶→栈底) | 说明 |
---|---|---|
0 | [i] | 加载参数i |
1-2 | [1, i] → [i+1] | 执行i+1运算 |
3-4 | [2, i+1] → [i-1] | 执行(i+1)-2运算 |
5-6 | [3, i-1] → [(i-1)*3] | 执行乘法运算 |
7-8 | [4, (i-1)3] → [(i-1)3/4] | 执行除法运算 |
9 | [] | ireturn 返回结果到调用者栈帧 |
总结
核心知识回顾
-
栈模型:操作数栈负责运算,局部变量区存储数据,两者通过
iload
/istore
系列指令交互。 -
指令分类:常数加载(
const
/push
/ldc
)、数组操作(newarray
/iaload
)、方法调用(invokevirtual
/invokestatic
)等指令构成字节码的核心功能。 -
类型安全:JVM通过指令严格检查数据类型(如
long
占2个槽,数组访问越界即时报错)。
实践与进阶建议
-
工具链:使用
javap -v ClassName
反编译查看字节码,结合jclasslib
可视化工具分析.class
文件结构。 -
字节码操作库:学习ASM、Javassist等库,实现动态代理(如Spring AOP)、字节码增强(如添加监控逻辑)。
-
JVM规范:阅读《Java Virtual Machine Specification》第6章,掌握每条指令的精确语义和异常处理逻辑。
Java字节码是连接高级语言与底层虚拟机的桥梁,其设计凝聚了跨平台、高效性和类型安全的核心思想。通过本文学习,希望大家能够从“使用Java”进阶到“理解Java”。
相关文章:
JVM——Java字节码基础
引入 Java字节码(Java Bytecode)是Java技术体系的核心枢纽,所有Java源码经过编译器处理后,最终都会转化为.class文件中的字节码指令。这些指令不依赖于具体的硬件架构和操作系统,而是由Java虚拟机(JVM&…...

控制台打印带格式内容
1. 场景 很多软件会在控制台打印带颜色和格式的文字,需要使用转义符实现这个功能。 2. 详细说明 2.1.转义符说明 样式开始:\033[参数1;参数2;参数3m 可以多个参数叠加,若同一类型的参数(如字体颜色)设置了多个&…...

外网访问内网海康威视监控视频的方案:WebRTC + Coturn 搭建
外网访问内网海康威视监控视频的方案:WebRTC Coturn 需求背景 在仓库中有海康威视的监控摄像头,内网中是可以直接访问到监控摄像的画面,由于项目的需求,需要在外网中也能看到监控画面。 实现这个功能的意义在于远程操控设备的…...
DA14585墨水屏学习(2)
一、user_svc2_wr_ind_handler函数 void user_svc2_wr_ind_handler(ke_msg_id_t const msgid,struct custs1_val_write_ind const *param,ke_task_id_t const dest_id,ke_task_id_t const src_id) {// sprintf(buf2,"HEX %d :",param->length);arch_printf("…...

Linux系统下的延迟任务及定时任务
1、延迟任务 概念: 在系统中我们的维护工作大多数时在服务器行对闲置时进行 我们需要用延迟任务来解决自动进行的一次性的维护 延迟任务时一次性的,不会重复执行 当延迟任务产生输出后,这些输出会以邮件的形式发送给延迟任务发起者 在 RH…...
Spark 之 YarnCoarseGrainedExecutorBackend
YarnCoarseGrainedExecutorBackend executor ID , 在日志里也有体现。 25/05/06 12:41:58 INFO YarnCoarseGrainedExecutorBackend: Successfully registered with driver 25/05...

【网络原理】数据链路层
目录 一. 以太网 二. 以太网数据帧 三. MAC地址 四. MTU 五. ARP协议 六. DNS 一. 以太网 以太网是一种基于有线或无线介质的计算机网络技术,定义了物理层和数据链路层的协议,用于在局域网中传输数据帧。 二. 以太网数据帧 1)目标地址 …...

相或为K(位运算)蓝桥杯(JAVA)
这个题是相或为k,考察相或的性质,用俩个数举例子,011001和011101后面的数不管和哪个数相或都不可能变成前面的数,所以利用这个性质我们可以用相与运算来把和k对应位置的1都积累起来,看最后能不能拼起来k如果能拼起来k那…...

AI汽车时代的全面赋能者:德赛西威全栈能力再升级
AI汽车未来智慧出行场景正在描绘出巨大的商业图景,德赛西威已经抢先入局。 在2025年上海车展开幕前夕,德赛西威发布2030年全新使命愿景——“创领安全、愉悦和绿色的出行生活”,并推出全栈式智慧出行解决方案Smart Solution3.0、车路云一体式…...
Python函数:从基础到进阶的完整指南
在Python编程中,函数是构建高效、可维护代码的核心工具。无论是开发Web应用、数据分析还是人工智能模型,函数都能将复杂逻辑模块化,提升代码复用率与团队协作效率。本文将从函数基础语法出发,深入探讨参数传递机制、高阶特性及最佳实践,助你掌握这一编程基石。 一、函数基…...

学习Python的第四天之网络爬虫
30岁程序员学习Python的第四天之网络爬虫的Scrapy库 Scrapy库的基本信息 Scrapy库的安装 在windows系统中通过管理员权限打开cmd。运行pip install scrapy即可安装。 通过命令scrapy -h可查看scrapy库是否安装成功. Scrapy库的基础信息 scrapy库是一种爬虫框架库 爬虫框…...

5、开放式PLC梯形图编程组件 - /自动化与控制组件/open-plc-programming
76个工业组件库示例汇总 开放式PLC编程环境 这是一个开放式PLC编程环境的自定义组件,提供了一个面向智能仓储堆垛机控制的开放式PLC编程环境。该组件采用苹果科技风格设计,支持多厂商PLC硬件,具有直观的界面和丰富的功能。 功能特点 多语…...
数据指标和数据标签
数据指标和数据标签是数据管理与分析中的两个重要概念,它们在用途、形式和应用场景上有显著区别。以下是两者的详细对比: 1. 核心定义 维度数据指标(Data Metrics)数据标签(Data Tags/Labels)定义量化衡量…...

linux中常用的命令(三)
目录 1- ls(查看当前目录下的内容) 2- pwd (查看当前所在的文件夹) 3- cd [目录名](切换文件夹) 4- touch [文件名] (如果文件不存在,新建文件) 5- mkdir[目录名] (创建目录) 6-rm[文件名]&…...

Java 中 AQS 的实现原理
AQS 简介 AQS(全称AbstractQueuedSynchronizer)即抽象同步队列,它是实现同步器的基础组件,并发包中锁的底层就是使用AQS实现的。 由类图可以看到,AQS是一个FIFO的双向队列,其内部通过节点head和tail记录队首和队尾元素࿰…...

『Python学习笔记』ubuntu解决matplotlit中文乱码的问题!
ubuntu解决matplotlit中文乱码的问题! 文章目录 simhei.ttf字体下载链接:http://xiazaiziti.com/210356.html将字体放到合适的地方 sudo cp SimHei.ttf /usr/share/fonts/(base) zkfzkf:~$ fc-list | grep -i "SimHei" /usr/local/share/font…...
docker compose ps 命令
docker compose ps 命令用于列出与 Docker Compose 项目相关的容器及其状态。 docker compose ps 能显示当前项目中所有服务容器的运行状态、端口映射等信息。 语法 docker compose ps [OPTIONS] [SERVICE…] SERVICE(可选):指定要查看状态…...
redis数据结构-04 (HINCRBY、HDEL、HKEYS、HVALS)
哈希操作:HINCRBY、HDEL、HKEYS、HVALS Redis 中的哈希功能极其丰富,让您能够以类似于编程语言中对象的方式存储和检索数据。本课将深入探讨具体的哈希操作,这些操作为操作以下结构中的数据提供了强大的工具: HINCRBY 、 HDEL 、…...

鸿蒙知识总结
判断题 1、 在http模块中,多个请求可以使用同一个httpRequest对象,httpRequest对象可以复用。(错误) 2、订阅dataReceiverProgress响应事件是用来接收HTTP流式响应数据。(错误) 3、ArkTS中变量声明时不需要…...
Ubuntu 22虚拟机【网络故障】快速解决指南
Ubuntu22虚拟机突然无法连接网络了,以下是故障排除步骤记录。 Ubuntu 22虚拟机网络故障快速解决指南 当在虚拟机中安装的 Ubuntu 22 系统出现 ping: connect: 网络不可达 和 ping: www.baidu.com: 域名解析出现暂时性错误的报错时,通常意味着虚拟机无法…...

C++23 新特性:深入解析 std::views::join_with(P2441R2)
文章目录 std::views::join_with 基本用法处理字符串集合std::views::join_with 与其他视图的结合使用总结 随着C23标准的逐步推进,我们迎来了许多令人兴奋的新特性,其中之一就是 std::views::join_with。这个新特性是C23中引入的视图适配器,…...
购物车构件示例
通用购物车构件设计 注:代码仅用于演示原理,不可用于生产环境。 一、设计目标 设计一个高度可复用的购物车构件,具备以下特点: 与具体业务系统解耦支持多种应用场景(商城、积分系统等)提供标准化接口易于集成和扩展二、核心架构设计 1. 分层架构 ┌─────────…...

数据可视化大屏——智慧社区内网比对平台
综述分析: 智慧社区内网数据比对信息系统 这段代码实现了一个智慧社区内网数据比对信息系统的前端界面,采用三栏式布局展示各类社区安全相关数据。界面主要由左侧数据统计、中间地图展示和右侧数据分析三部分组成,使用了多种图表可视化技术…...
详解SLAM中的李群和李代数(中)
1 概述 在上一篇文章《详解SLAM中的李群和李代数(上)》中,我们已经通过对李群求导引出了李代数。在这篇文章中,我们就系统总结一下李代数的相关知识。 2 李代数 2.1 定义 李代数是一个向量空间 g \mathfrak{g} g与一个二元运算…...

Jenkins企业级实战
目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包(JDK) Jenkins是基于Java的应用程序,因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…...

uniapp-商城-52-后台 商家信息(商家信息数据,云对象使用)
1、概述 已经通过好几个篇幅来说明商家信息,包括logo、商家名称,地址,电话以及商家简介。通过表单组件和标签,以及我们的文件上传标签,都做了说明。(logo上传,用的文件上传组件是上传到公共的数…...

MySQL 索引设计宝典:原理、原则与实战案例深度解析
目录 前言第一章:索引设计的基础原则 (知其然,更要知其所以然)第二章:实战案例:电商订单系统的索引设计第三章:索引设计的实践流程总结结语 🌟我的其他文章也讲解的比较有趣😁,如果喜…...

C#上传文件到腾讯云的COS
测试环境: vs2022 .net 6控制台应用程序 测试步骤如下: 1 添加子用户,目前是为了拿到secretId和secretKey,打开添加子用户界面链接:https://console.cloud.tencent.com/cam 并为子用户添加API 密钥 2 通过链接htt…...
java的Stream流处理
Java Stream 流处理详解 Stream 是 Java 8 引入的一个强大的数据处理抽象,它允许你以声明式方式处理数据集合(类似于 SQL 语句),支持并行操作,提高了代码的可读性和处理效率。 一、Stream 的核心概念 1. 什么是 Str…...

C PRIMER PLUS——第9节:动态内存分配、存储类别、链接和内存管理
目录 1.动态内存分配 1.1 malloc 函数 1.2 calloc 函数 1.3 realloc 函数 1.4 free 函数 1.5常见错误 1.6综合例题 2.C语言的内存结构 3.存储类别 3.1作用域(Scope) 3.2链接(Linkage) 3.3存储期(Storage Du…...