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

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优化策略

  1. 避免冗余压栈:复用栈顶临时结果,减少dup/pop操作。

  2. 限制递归深度:对深度递归方法(如斐波那契递归),改用循环或尾递归优化。

示例分析:加法运算的栈操作全过程

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系列)

数据类型指令支持值范围操作码示例说明
inticonst_m1-10x02iconst_m1 → 压入-1仅支持-1~5,共7个特定值
iconst_0-iconst_50~50x03-0x08iconst_3 → 压入3操作码紧凑,无需操作数
longlconst_00L0x09lconst_0 → 压入0L仅支持0L和1L,占2个栈单元
lconst_11L0x0Alconst_1 → 压入1L
floatfconst_00.0f0x0Bfconst_0 → 压入0.0f仅支持0.0f、1.0f、2.0f
fconst_11.0f0x0Cfconst_1 → 压入1.0f
fconst_22.0f0x0Dfconst_2 → 压入2.0f
doubledconst_00.0d0x0Edconst_0 → 压入0.0d仅支持0.0d和1.0d,占2个栈单元
dconst_11.0d0x0Fdconst_1 → 压入1.0d
引用类型aconst_nullnull引用0x01aconst_null → 压入null唯一直接加载引用的非常量指令

中等范围整数加载指令(push系列)

指令数据类型支持值范围操作数长度示例说明
bipushint-128~127(1字节)1字节bipush 100 → 压入100用于单字节表示的整数
sipushint-32768~32767(2字节)2字节sipush 10000 → 压入10000用于双字节表示的整数

通用常量加载指令(ldc系列)

指令数据类型功能描述操作数示例说明
ldcint/float/String/Class加载常量池中的对应类型常量1字节索引ldc #18 → 加载常量池第18项最灵活的常量加载方式
ldc_w同上支持更大范围的常量池索引(2字节)2字节索引ldc_w #256 → 加载第256项用于常量池索引超过255的场景
ldc2_wlong/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 iString s共享同一槽),节省内存空间。

局部变量访问指令表:加载与存储的类型安全控制

访问指令严格区分数据类型,分为加载(Load)存储(Store)两类,如下表所示:

数据类型加载指令(局部变量→栈)存储指令(栈→局部变量)简化形式(索引0-3)说明
int/boolean/byte/char/shortiload [n]istore [n]iload_0-iload_3加载时自动转型为int,存储时截断
longlload [n]lstore [n]lload_0-lload_3占用连续两个槽(n和n+1)
floatfload [n]fstore [n]fload_0-fload_3单精度浮点,直接存储为4字节
doubledload [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=intnewarray int → 创建int数组T可选intbytechar
anewarray C创建引用类型数组2字节类名索引(常量池)anewarray java/lang/String → 创建String数组数组元素初始化为null
multianewarray A N创建多维数组类名索引A + 各维度长度Nmultianewarray [[I 2 → 创建2维int数组N为维度参数,如{2, 3}表示2×3数组

数组元素访问指令(按类型区分)

元素类型加载指令(取元素→栈)存储指令(栈→元素)指令执行前栈状态(从顶到底)说明
boolean/bytebaloadbastore[arrayRef, index, value](存储时)booleanbyte共用指令
charcaloadcastore[arrayRef, index](加载时)加载char为16位无符号整数
shortsaloadsastore存储时自动截断为16位
intialoadiastore最常用的数组访问指令
longlaloadlastore[arrayRef, index](加载后栈顶为8字节long)占用2个栈单元
floatfaloadfastore单精度浮点,4字节存储
doubledaloaddastore双精度浮点,占用2个栈单元
引用类型aaloadaastore[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类,确保数据正确传递给调用者,下表为详细分类:

返回值类型返回指令功能描述字节码示例栈操作(执行前)说明
voidreturn无返回值,结束方法执行return栈可为空或任意状态用于void方法或构造器
intireturn返回int类型值ireturn栈顶为int自动处理boolean/byte/char/short的返回
longlreturn返回long类型值lreturn栈顶为long值(占2个单元)弹出2个栈单元,返回64位长整型
floatfreturn返回float类型值freturn栈顶为float按IEEE 754单精度格式返回
doubledreturn返回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返回结果到调用者栈帧

总结

核心知识回顾

  1. 栈模型:操作数栈负责运算,局部变量区存储数据,两者通过iload/istore系列指令交互。

  2. 指令分类:常数加载(const/push/ldc)、数组操作(newarray/iaload)、方法调用(invokevirtual/invokestatic)等指令构成字节码的核心功能。

  3. 类型安全:JVM通过指令严格检查数据类型(如long占2个槽,数组访问越界即时报错)。

实践与进阶建议

  • 工具链:使用javap -v ClassName反编译查看字节码,结合jclasslib可视化工具分析.class文件结构。

  • 字节码操作库:学习ASM、Javassist等库,实现动态代理(如Spring AOP)、字节码增强(如添加监控逻辑)。

  • JVM规范:阅读《Java Virtual Machine Specification》第6章,掌握每条指令的精确语义和异常处理逻辑。

Java字节码是连接高级语言与底层虚拟机的桥梁,其设计凝聚了跨平台、高效性和类型安全的核心思想。通过本文学习,希望大家能够从“使用Java”进阶到“理解Java”。

相关文章:

JVM——Java字节码基础

引入 Java字节码&#xff08;Java Bytecode&#xff09;是Java技术体系的核心枢纽&#xff0c;所有Java源码经过编译器处理后&#xff0c;最终都会转化为.class文件中的字节码指令。这些指令不依赖于具体的硬件架构和操作系统&#xff0c;而是由Java虚拟机&#xff08;JVM&…...

控制台打印带格式内容

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

外网访问内网海康威视监控视频的方案:WebRTC + Coturn 搭建

外网访问内网海康威视监控视频的方案&#xff1a;WebRTC Coturn 需求背景 在仓库中有海康威视的监控摄像头&#xff0c;内网中是可以直接访问到监控摄像的画面&#xff0c;由于项目的需求&#xff0c;需要在外网中也能看到监控画面。 实现这个功能的意义在于远程操控设备的…...

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、延迟任务 概念&#xff1a; 在系统中我们的维护工作大多数时在服务器行对闲置时进行 我们需要用延迟任务来解决自动进行的一次性的维护 延迟任务时一次性的&#xff0c;不会重复执行 当延迟任务产生输出后&#xff0c;这些输出会以邮件的形式发送给延迟任务发起者 在 RH…...

Spark 之 YarnCoarseGrainedExecutorBackend

YarnCoarseGrainedExecutorBackend executor ID , 在日志里也有体现。 25/05/06 12:41:58 INFO YarnCoarseGrainedExecutorBackend: Successfully registered with driver 25/05...

【网络原理】数据链路层

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

相或为K(位运算)蓝桥杯(JAVA)

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

AI汽车时代的全面赋能者:德赛西威全栈能力再升级

AI汽车未来智慧出行场景正在描绘出巨大的商业图景&#xff0c;德赛西威已经抢先入局。 在2025年上海车展开幕前夕&#xff0c;德赛西威发布2030年全新使命愿景——“创领安全、愉悦和绿色的出行生活”&#xff0c;并推出全栈式智慧出行解决方案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编程环境的自定义组件&#xff0c;提供了一个面向智能仓储堆垛机控制的开放式PLC编程环境。该组件采用苹果科技风格设计&#xff0c;支持多厂商PLC硬件&#xff0c;具有直观的界面和丰富的功能。 功能特点 多语…...

数据指标和数据标签

数据指标和数据标签是数据管理与分析中的两个重要概念&#xff0c;它们在用途、形式和应用场景上有显著区别。以下是两者的详细对比&#xff1a; 1. 核心定义 维度数据指标&#xff08;Data Metrics&#xff09;数据标签&#xff08;Data Tags/Labels&#xff09;定义量化衡量…...

linux中常用的命令(三)

目录 1- ls(查看当前目录下的内容) 2- pwd (查看当前所在的文件夹) 3- cd [目录名]&#xff08;切换文件夹&#xff09; 4- touch [文件名] &#xff08;如果文件不存在&#xff0c;新建文件&#xff09; 5- mkdir[目录名] &#xff08;创建目录&#xff09; 6-rm[文件名]&…...

Java 中 AQS 的实现原理

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

『Python学习笔记』ubuntu解决matplotlit中文乱码的问题!

ubuntu解决matplotlit中文乱码的问题&#xff01; 文章目录 simhei.ttf字体下载链接&#xff1a;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&#xff08;可选&#xff09;&#xff1a;指定要查看状态…...

redis数据结构-04 (HINCRBY、HDEL、HKEYS、HVALS)

哈希操作&#xff1a;HINCRBY、HDEL、HKEYS、HVALS Redis 中的哈希功能极其丰富&#xff0c;让您能够以类似于编程语言中对象的方式存储和检索数据。本课将深入探讨具体的哈希操作&#xff0c;这些操作为操作以下结构中的数据提供了强大的工具&#xff1a; HINCRBY 、 HDEL 、…...

鸿蒙知识总结

判断题 1、 在http模块中&#xff0c;多个请求可以使用同一个httpRequest对象&#xff0c;httpRequest对象可以复用。&#xff08;错误&#xff09; 2、订阅dataReceiverProgress响应事件是用来接收HTTP流式响应数据。&#xff08;错误&#xff09; 3、ArkTS中变量声明时不需要…...

Ubuntu 22虚拟机【网络故障】快速解决指南

Ubuntu22虚拟机突然无法连接网络了&#xff0c;以下是故障排除步骤记录。 Ubuntu 22虚拟机网络故障快速解决指南 当在虚拟机中安装的 Ubuntu 22 系统出现 ping: connect: 网络不可达 和 ping: www.baidu.com: 域名解析出现暂时性错误的报错时&#xff0c;通常意味着虚拟机无法…...

C++23 新特性:深入解析 std::views::join_with(P2441R2)

文章目录 std::views::join_with 基本用法处理字符串集合std::views::join_with 与其他视图的结合使用总结 随着C23标准的逐步推进&#xff0c;我们迎来了许多令人兴奋的新特性&#xff0c;其中之一就是 std::views::join_with。这个新特性是C23中引入的视图适配器&#xff0c…...

购物车构件示例

通用购物车构件设计 注:代码仅用于演示原理,不可用于生产环境。 一、设计目标 设计一个高度可复用的购物车构件,具备以下特点: 与具体业务系统解耦支持多种应用场景(商城、积分系统等)提供标准化接口易于集成和扩展二、核心架构设计 1. 分层架构 ┌─────────…...

数据可视化大屏——智慧社区内网比对平台

综述分析&#xff1a; 智慧社区内网数据比对信息系统 这段代码实现了一个智慧社区内网数据比对信息系统的前端界面&#xff0c;采用三栏式布局展示各类社区安全相关数据。界面主要由左侧数据统计、中间地图展示和右侧数据分析三部分组成&#xff0c;使用了多种图表可视化技术…...

详解SLAM中的李群和李代数(中)

1 概述 在上一篇文章《详解SLAM中的李群和李代数&#xff08;上&#xff09;》中&#xff0c;我们已经通过对李群求导引出了李代数。在这篇文章中&#xff0c;我们就系统总结一下李代数的相关知识。 2 李代数 2.1 定义 李代数是一个向量空间 g \mathfrak{g} g与一个二元运算…...

Jenkins企业级实战

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

uniapp-商城-52-后台 商家信息(商家信息数据,云对象使用)

1、概述 已经通过好几个篇幅来说明商家信息&#xff0c;包括logo、商家名称&#xff0c;地址&#xff0c;电话以及商家简介。通过表单组件和标签&#xff0c;以及我们的文件上传标签&#xff0c;都做了说明。&#xff08;logo上传&#xff0c;用的文件上传组件是上传到公共的数…...

MySQL 索引设计宝典:原理、原则与实战案例深度解析

目录 前言第一章&#xff1a;索引设计的基础原则 (知其然&#xff0c;更要知其所以然)第二章&#xff1a;实战案例&#xff1a;电商订单系统的索引设计第三章&#xff1a;索引设计的实践流程总结结语 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&#xff0c;如果喜…...

C#上传文件到腾讯云的COS

测试环境&#xff1a; vs2022 .net 6控制台应用程序 测试步骤如下&#xff1a; 1 添加子用户&#xff0c;目前是为了拿到secretId和secretKey&#xff0c;打开添加子用户界面链接&#xff1a;https://console.cloud.tencent.com/cam 并为子用户添加API 密钥 2 通过链接htt…...

java的Stream流处理

Java Stream 流处理详解 Stream 是 Java 8 引入的一个强大的数据处理抽象&#xff0c;它允许你以声明式方式处理数据集合&#xff08;类似于 SQL 语句&#xff09;&#xff0c;支持并行操作&#xff0c;提高了代码的可读性和处理效率。 一、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作用域&#xff08;Scope&#xff09; 3.2链接&#xff08;Linkage&#xff09; 3.3存储期&#xff08;Storage Du…...