JVM 之 字节码指令
目录
一. 前言
二. 指令集
2.1. 支持的数据类型
2.2. 指令分类
三. 指令手册
3.1. 操作数栈
3.2. 运算与转换
3.3. 条件转移
3.4. 类与数组
3.5. 调度与返回加 finally
3.6. 指令手册汇总
3.7. 示例
一. 前言
字节码指令集的特点是数据量短小精干,便于传输,跨平台。同时也损失一定的解释执行效率。
1. 由 操作码 + 操作数组成。 JVM的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。
2. 指令集的操作码是单字节的,总数不可能超过256条。为了尽可能获得短小精干的编译代码。
3. 操作数的长度不对齐,长度超过1字节的以big一endian顺序存储,即高位在前的字节序。如:两个无符号字节存储的值就是:(byte1<<8)|byte2。不对齐可省略很多填充和间隔符号。
4. 字节码指令流单字节对齐,但除Iableswitch和lookupswitch两个指令例外(4字节为界,少的补空)。
二. 指令集
2.1. 支持的数据类型
JVM指令集中,大多数的指令都包含了其所操作的数据类型信息。数据类型相关的操作码助记符中的首字母都跟操作的数据类型相关:i代表对int类型的数据操作,l代表 long ,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。
指令集并非支持所有类型,byte、char、short、boolean 等类型,都用操作数的运算类型(computational type)为int的指令来完成。byte和short类型的数据带符号扩展(sign-extend)为相应的int类型数据,boolean和char类型数据零位扩展(zero-extend)为相应的int类型数据。
2.2. 指令分类
1. 加载和存储指令,加载存储指令用于局部变量与操作数栈交换数据以及常量装载到操作数栈,如push、load、store、const。按数据类型不同在指令前面加i/l/f/d/a等,操作数放指令后面,超过4直接写下标,例:iload_3、iload 4。
2. 运算指令,加add、减sub、乘mul、除div、求余rem、取反neg、移位sh(l左r右)、与and、或or、异或xor、自增inc、cmp比较。
3. 类型转换指令,2(to),表示操作类型 到 目标类型,从小字节类型转大是宽化指令,从大字节类型转小窄化指令。
4. 对象创建与访问指令,创建对象new、创建基本类型数组newarray、创建引用类型数组anewarray、创建多维数组multianewarray。
5. 操作数栈管理指令,出栈pop、交换swap、复制栈顶并压栈dup。
6. 控制转移指令,条件跳转指令:if与eq/ne/lt/le/gt/ge组合(与0比较或加cmp表示栈顶两个操作数比较)、复合条件跳转指令tableswitch与lookupswitch、无条件跳转指令goto。
7. 方法调用和返回指令,调用对象的实例方法invokevirtual、调用接口方法invokeinterface、调用特殊实例方法invokespecial(如初始化方法)、调用类静态方法invokestatic、调用动态链接方法invokedynamic。返回指令return(带类型)、(以及SE6之前的jsr、ret)。
8. 异常处理指令,athrow。
9. 同步指令,monitorenter monitorexit。
三. 指令手册
3.1. 操作数栈
过程 | 符号 |
---|---|
变量到操作数栈 | iload, iload_, lload, lload_, fload, fload_, dload, dload_, aload, aload_ |
操作数栈到变量 | istore, istore_, lstore, lstore_, fstore, fstore_, dstore, dstor_, astore, astore_ |
常数到操作数栈 | bipush, sipush, ldc, ldc_w, ldc2_w, aconst_null, iconst_ml, iconst_, lconst_, fconst_, dconst_ |
把数据装载到操作数栈 | baload, caload, saload, iaload, laload, faload, daload, aaload |
从操作数栈存存储到数组 | bastore, castore, sastore, iastore, lastore, fastore, dastore, aastore |
操作数栈管理 | pop, pop2, dup, dup2, dup_xl, dup2_xl, dup_x2, dup2_x2, swap |
3.2. 运算与转换
过程 | 符号 |
---|---|
加 | iadd, ladd, fadd, dadd |
减 | is, ls, fs, ds |
乘 | imul, lmul, fmul, dmul |
除 | idiv, ldiv, fdiv, ddiv |
余数 | irem, lrem, frem, drem |
取负 | ineg, lneg, fneg, dneg |
移位 | ishl, lshr, iushr, lshl, lshr, lushr |
按位或 | ior, lor |
按位与 | iand, land |
按位异或 | ixor, lxor |
类型转换 | i2l, i2f, i2d, l2f, l2d, f2d(放宽数值转换); i2b, i2c, i2s, l2i, f2i, f2l, d2i, d2l, d2f(缩窄数值转换) |
3.3. 条件转移
过程 | 符号 |
---|---|
有条件转移 | ifeq, iflt, ifle, ifne, ifgt, ifge, ifnull, ifnonnull, if_icmpeq, if_icmpene, if_icmplt, if_icmpgt, if_icmple, if_icmpge, if_acmpeq, if_acmpne, lcmp, fcmpl, fcmpg, dcmpl, dcmpg |
复合条件转移 | tableswitch, lookupswitch |
无条件转移 | goto, goto_w, jsr, jsr_w, ret |
3.4. 类与数组
过程 | 符号 |
---|---|
创建类实便 | new |
创建新数组 | newarray, anewarray, multianwarray |
访问类的域和类实例域 | getfield, putfield, getstatic, putstatic |
获取数组长度 | arraylength |
检相类实例或数组属性 | instanceof, checkcast |
3.5. 调度与返回加 finally
过程 | 符号 |
---|---|
调度对象的实便方法 | invokevirt l |
调用由接口实现的方法 | invokeinterface |
调用需要特殊处理的实例方法 | invokespecial |
调用命名类中的静态方法 | invokestatic |
方法返回 | ireturn, lreturn, freturn, dreturn, areturn, return |
异常 | athrow |
finally 关键字的实现使用 | jsr, jsr_w, ret |
3.6. 指令手册汇总
指令码 | 助记符 | 说明 |
---|---|---|
0x00 | nop | 什么都不做 |
0x01 | aconst_null | 将 null 推送至栈顶 |
0x02 | iconst_m1 | 将 int 型 -1 推送至栈顶 |
0x03 | iconst_0 | 将 int 型 0 推送至栈顶 |
0x04 | iconst_1 | 将 int 型 1 推送至栈顶 |
0x05 | iconst_2 | 将 int 型 2 推送至栈顶 |
0x06 | iconst_3 | 将 int 型 3 推送至栈顶 |
0x07 | iconst_4 | 将 int 型 4 推送至栈顶 |
0x08 | iconst_5 | 将 int 型 5 推送至栈顶 |
0x09 | lconst_0 | 将 long 型 0 推送至栈顶 |
0x0a | lconst_1 | 将 long 型 1 推送至栈顶 |
0x0b | fconst_0 | 将 float 型 0 推送至栈顶 |
0x0c | fconst_1 | 将 float 型 1 推送至栈顶 |
0x0d | fconst_2 | 将 float 型 2 推送至栈顶 |
0x0e | dconst_0 | 将 double 型 0 推送至栈顶 |
0x0f | dconst_1 | 将 double 型 1 推送至栈顶 |
0x10 | bipush | 将单字节的常量值 (-128~127) 推送至栈顶 |
0x11 | sipush | 将一个短整型常量值 (-32768~32767) 推送至栈顶 |
0x12 | ldc | 将int, |
0x13 | ldc_w | 将int, |
0x14 | ldc2_w | 将 long 或 double 型常量值从常量池中推送至栈顶(宽索引) |
0x15 | iload | 将指定的 int 型本地变量推送至栈顶 |
0x16 | lload | 将指定的 long 型本地变量推送至栈顶 |
0x17 | fload | 将指定的 float 型本地变量推送至栈顶 |
0x18 | dload | 将指定的 double 型本地变量推送至栈顶 |
0x19 | aload | 将指定的引用类型本地变量推送至栈顶 |
0x1a | iload_0 | 将第一个 int 型本地变量推送至栈顶 |
0x1b | iload_1 | 将第二个 int 型本地变量推送至栈顶 |
0x1c | iload_2 | 将第三个 int 型本地变量推送至栈顶 |
0x1d | iload_3 | 将第四个 int 型本地变量推送至栈顶 |
0x1e | lload_0 | 将第一个 long 型本地变量推送至栈顶 |
0x1f | lload_1 | 将第二个 long 型本地变量推送至栈顶 |
0x20 | lload_2 | 将第三个 long 型本地变量推送至栈顶 |
0x21 | lload_3 | 将第四个 long 型本地变量推送至栈顶 |
0x22 | fload_0 | 将第一个 float 型本地变量推送至栈顶 |
0x23 | fload_1 | 将第二个 float 型本地变量推送至栈顶 |
0x24 | fload_2 | 将第三个 float 型本地变量推送至栈顶 |
0x25 | fload_3 | 将第四个 float 型本地变量推送至栈顶 |
0x26 | dload_0 | 将第一个 double 型本地变量推送至栈顶 |
0x27 | dload_1 | 将第二个 double 型本地变量推送至栈顶 |
0x28 | dload_2 | 将第三个 double 型本地变量推送至栈顶 |
0x29 | dload_3 | 将第四个 double 型本地变量推送至栈顶 |
0x2a | aload_0 | 将第一个引用类型本地变量推送至栈顶 |
0x2b | aload_1 | 将第二个引用类型本地变量推送至栈顶 |
0x2c | aload_2 | 将第三个引用类型本地变量推送至栈顶 |
0x2d | aload_3 | 将第四个引用类型本地变量推送至栈顶 |
0x2e | iaload | 将 int 型数组指定索引的值推送至栈顶 |
0x2f | laload | 将 long 型数组指定索引的值推送至栈顶 |
0x30 | faload | 将 float 型数组指定索引的值推送至栈顶 |
0x31 | daload | 将 double 型数组指定索引的值推送至栈顶 |
0x32 | aaload | 将引用型数组指定索引的值推送至栈顶 |
0x33 | baload | 将 boolean 或 byte 型数组指定索引的值推送至栈顶 |
0x34 | caload | 将 char 型数组指定索引的值推送至栈顶 |
0x35 | saload | 将 short 型数组指定索引的值推送至栈顶 |
0x36 | istore | 将栈顶 int 型数值存入指定本地变量 |
0x37 | lstore | 将栈顶 long 型数值存入指定本地变量 |
0x38 | fstore | 将栈顶 float 型数值存入指定本地变量 |
0x39 | dstore | 将栈顶 double 型数值存入指定本地变量 |
0x3a | astore | 将栈顶引用型数值存入指定本地变量 |
0x3b | istore_0 | 将栈顶 int 型数值存入第一个本地变量 |
0x3c | istore_1 | 将栈顶 int 型数值存入第二个本地变量 |
0x3d | istore_2 | 将栈顶 int 型数值存入第三个本地变量 |
0x3e | istore_3 | 将栈顶 int 型数值存入第四个本地变量 |
0x3f | lstore_0 | 将栈顶 long 型数值存入第一个本地变量 |
0x40 | lstore_1 | 将栈顶 long 型数值存入第二个本地变量 |
0x41 | lstore_2 | 将栈顶 long 型数值存入第三个本地变量 |
0x42 | lstore_3 | 将栈顶 long 型数值存入第四个本地变量 |
0x43 | fstore_0 | 将栈顶 float 型数值存入第一个本地变量 |
0x44 | fstore_1 | 将栈顶 float 型数值存入第二个本地变量 |
0x45 | fstore_2 | 将栈顶 float 型数值存入第三个本地变量 |
0x46 | fstore_3 | 将栈顶 float 型数值存入第四个本地变量 |
0x47 | dstore_0 | 将栈顶 double 型数值存入第一个本地变量 |
0x48 | dstore_1 | 将栈顶 double 型数值存入第二个本地变量 |
0x49 | dstore_2 | 将栈顶 double 型数值存入第三个本地变量 |
0x4a | dstore_3 | 将栈顶 double 型数值存入第四个本地变量 |
0x4b | astore_0 | 将栈顶引用型数值存入第一个本地变量 |
0x4c | astore_1 | 将栈顶引用型数值存入第二个本地变量 |
0x4d | astore_2 | 将栈顶引用型数值存入第三个本地变量 |
0x4e | astore_3 | 将栈顶引用型数值存入第四个本地变量 |
0x4f | iastore | 将栈顶 int 型数值存入指定数组的指定索引位置 |
0x50 | lastore | 将栈顶 long 型数值存入指定数组的指定索引位置 |
0x51 | fastore | 将栈顶 float 型数值存入指定数组的指定索引位置 |
0x52 | dastore | 将栈顶 double 型数值存入指定数组的指定索引位置 |
0x53 | aastore | 将栈顶引用型数值存入指定数组的指定索引位置 |
0x54 | bastore | 将栈顶 boolean 或 byte 型数值存入指定数组的指定索引位置 |
0x55 | castore | 将栈顶 char 型数值存入指定数组的指定索引位置 |
0x56 | sastore | 将栈顶 short 型数值存入指定数组的指定索引位置 |
0x57 | pop | 将栈顶数值弹出 |
0x58 | pop2 | 将栈顶的一个(long 或 double 类型的)或两个数值弹出(其它) |
0x59 | dup | 复制栈顶数值并将复制值压入栈顶 |
0x5a | dup_x1 | 复制栈顶数值并将两个复制值压入栈顶 |
0x5b | dup_x2 | 复制栈顶数值并将三个(或两个)复制值压入栈顶 |
0x5c | dup2 | 复制栈顶一个(long 或 double 类型的)或两个(其它)数值并将复制值压入栈顶 |
0x5d | dup2_x1 | <待补充> |
0x5e | dup2_x2 | <待补充> |
0x5f | swap | 将栈最顶端的两个数值互换(数值不能是 long 或 double 类型的) |
0x60 | iadd | 将栈顶两 int 型数值相加并将结果压入栈顶 |
0x61 | ladd | 将栈顶两 long 型数值相加并将结果压入栈顶 |
0x62 | fadd | 将栈顶两 float 型数值相加并将结果压入栈顶 |
0x63 | dadd | 将栈顶两 double 型数值相加并将结果压入栈顶 |
0x64 | isub | 将栈顶两 int 型数值相减并将结果压入栈顶 |
0x65 | lsub | 将栈顶两 long 型数值相减并将结果压入栈顶 |
0x66 | fsub | 将栈顶两 float 型数值相减并将结果压入栈顶 |
0x67 | dsub | 将栈顶两 double 型数值相减并将结果压入栈顶 |
0x68 | imul | 将栈顶两 int 型数值相乘并将结果压入栈顶 |
0x69 | lmul | 将栈顶两 long 型数值相乘并将结果压入栈顶 |
0x6a | fmul | 将栈顶两 float 型数值相乘并将结果压入栈顶 |
0x6b | dmul | 将栈顶两 double 型数值相乘并将结果压入栈顶 |
0x6c | idiv | 将栈顶两 int 型数值相除并将结果压入栈顶 |
0x6d | ldiv | 将栈顶两 long 型数值相除并将结果压入栈顶 |
0x6e | fdiv | 将栈顶两 float 型数值相除并将结果压入栈顶 |
0x6f | ddiv | 将栈顶两 double 型数值相除并将结果压入栈顶 |
0x70 | irem | 将栈顶两 int 型数值作取模运算并将结果压入栈顶 |
0x71 | lrem | 将栈顶两 long 型数值作取模运算并将结果压入栈顶 |
0x72 | frem | 将栈顶两 float 型数值作取模运算并将结果压入栈顶 |
0x73 | drem | 将栈顶两 double 型数值作取模运算并将结果压入栈顶 |
0x74 | ineg | 将栈顶 int 型数值取负并将结果压入栈顶 |
0x75 | lneg | 将栈顶 long 型数值取负并将结果压入栈顶 |
0x76 | fneg | 将栈顶 float 型数值取负并将结果压入栈顶 |
0x77 | dneg | 将栈顶 double 型数值取负并将结果压入栈顶 |
0x78 | ishl | 将 int 型数值左移位指定位数并将结果压入栈顶 |
0x79 | lshl | 将 long 型数值左移位指定位数并将结果压入栈顶 |
0x7a | ishr | 将 int 型数值右(符号)移位指定位数并将结果压入栈顶 |
0x7b | lshr | 将 long 型数值右(符号)移位指定位数并将结果压入栈顶 |
0x7c | iushr | 将 int 型数值右(无符号)移位指定位数并将结果压入栈顶 |
0x7d | lushr | 将 long 型数值右(无符号)移位指定位数并将结果压入栈顶 |
0x7e | iand | 将栈顶两 int 型数值作“按位与”并将结果压入栈顶 |
0x7f | land | 将栈顶两 long 型数值作“按位与”并将结果压入栈顶 |
0x80 | ior | 将栈顶两 int 型数值作“按位或”并将结果压入栈顶 |
0x81 | lor | 将栈顶两 long 型数值作“按位或”并将结果压入栈顶 |
0x82 | ixor | 将栈顶两 int 型数值作“按位异或”并将结果压入栈顶 |
0x83 | lxor | 将栈顶两 long 型数值作“按位异或”并将结果压入栈顶 |
0x84 | iinc | 将指定 int 型变量增加指定值(i++, |
0x85 | i2l | 将栈顶 int 型数值强制转换成 long 型数值并将结果压入栈顶 |
0x86 | i2f | 将栈顶 int 型数值强制转换成 float 型数值并将结果压入栈顶 |
0x87 | i2d | 将栈顶 int 型数值强制转换成 double 型数值并将结果压入栈顶 |
0x88 | l2i | 将栈顶 long 型数值强制转换成 int 型数值并将结果压入栈顶 |
0x89 | l2f | 将栈顶 long 型数值强制转换成 float 型数值并将结果压入栈顶 |
0x8a | l2d | 将栈顶 long 型数值强制转换成 double 型数值并将结果压入栈顶 |
0x8b | f2i | 将栈顶 float 型数值强制转换成 int 型数值并将结果压入栈顶 |
0x8c | f2l | 将栈顶 float 型数值强制转换成 long 型数值并将结果压入栈顶 |
0x8d | f2d | 将栈顶 float 型数值强制转换成 double 型数值并将结果压入栈顶 |
0x8e | d2i | 将栈顶 double 型数值强制转换成 int 型数值并将结果压入栈顶 |
0x8f | d2l | 将栈顶 double 型数值强制转换成 long 型数值并将结果压入栈顶 |
0x90 | d2f | 将栈顶 double 型数值强制转换成 float 型数值并将结果压入栈顶 |
0x91 | i2b | 将栈顶 int 型数值强制转换成 byte 型数值并将结果压入栈顶 |
0x92 | i2c | 将栈顶 int 型数值强制转换成 char 型数值并将结果压入栈顶 |
0x93 | i2s | 将栈顶 int 型数值强制转换成 short 型数值并将结果压入栈顶 |
0x94 | lcmp | 比较栈顶两 long 型数值大小,并将结果(1,0,-1)压入栈顶 |
0x95 | fcmpl | 比较栈顶两 float 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 NaN 时,将 -1 压入栈顶 |
0x96 | fcmpg | 比较栈顶两 float 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 NaN 时,将 1 压入栈顶 |
0x97 | dcmpl | 比较栈顶两 double 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 NaN 时,将 -1 压入栈顶 |
0x98 | dcmpg | 比较栈顶两 double 型数值大小,并将结果(1,0,-1)压入栈顶;当其中一个数值为 NaN 时,将 1 压入栈顶 |
0x99 | ifeq | 当栈顶 int 型数值等于 0 时跳转 |
0x9a | ifne | 当栈顶 int 型数值不等于 0 时跳转 |
0x9b | iflt | 当栈顶 int 型数值小于 0 时跳转 |
0x9c | ifge | 当栈顶 int 型数值大于等于 0 时跳转 |
0x9d | ifgt | 当栈顶 int 型数值大于 0 时跳转 |
0x9e | ifle | 当栈顶 int 型数值小于等于 0 时跳转 |
0x9f | if_icmpeq | 比较栈顶两 int 型数值大小,当结果等于 0 时跳转 |
0xa0 | if_icmpne | 比较栈顶两 int 型数值大小,当结果不等于 0 时跳转 |
0xa1 | if_icmplt | 比较栈顶两 int 型数值大小,当结果小于 0 时跳转 |
0xa2 | if_icmpge | 比较栈顶两 int 型数值大小,当结果大于等于 0 时跳转 |
0xa3 | if_icmpgt | 比较栈顶两 int 型数值大小,当结果大于 0 时跳转 |
0xa4 | if_icmple | 比较栈顶两 int 型数值大小,当结果小于等于 0 时跳转 |
0xa5 | if_acmpeq | 比较栈顶两引用型数值,当结果相等时跳转 |
0xa6 | if_acmpne | 比较栈顶两引用型数值,当结果不相等时跳转 |
0xa7 | goto | 无条件跳转 |
0xa8 | jsr | 跳转至指定 16 位 offset 位置,并将 jsr 下一条指令地址压入栈顶 |
0xa9 | ret | 返回至本地变量指定的 index 的指令位置(一般与 jsr, jsr_w 联合使用) |
0xaa | tableswitch | 用于 switch 条件跳转,case 值连续(可变长度指令) |
0xab | lookupswitch | 用于 switch 条件跳转,case 值不连续(可变长度指令) |
0xac | ireturn | 从当前方法返回 int |
0xad | lreturn | 从当前方法返回 long |
0xae | freturn | 从当前方法返回 float |
0xaf | dreturn | 从当前方法返回 double |
0xb0 | areturn | 从当前方法返回对象引用 |
0xb1 | return | 从当前方法返回void |
0xb2 | getstatic | 获取指定类的静态域,并将其值压入栈顶 |
0xb3 | putstatic | 为指定的类的静态域赋值 |
0xb4 | getfield | 获取指定类的实例域,并将其值压入栈顶 |
0xb5 | putfield | 为指定的类的实例域赋值 |
0xb6 | invokevirtual | 调用实例方法 |
0xb7 | invokespecial | 调用超类构造方法,实例初始化方法,私有方法 |
0xb8 | invokestatic | 调用静态方法 |
0xb9 | invokeinterface | 调用接口方法 |
0xba | – | |
0xbb | new | 创建一个对象,并将其引用值压入栈顶 |
0xbc | newarray | 创建一个指定原始类型(如int, float, char…)的数组,并将其引用值压入栈顶 |
0xbd | anewarray | 创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶 |
0xbe | arraylength | 获得数组的长度值并压入栈顶 |
0xbf | athrow | 将栈顶的异常抛出 |
0xc0 | checkcast | 检验类型转换,检验未通过将抛出 ClassCastException |
0xc1 | instanceof | 检验对象是否是指定的类的实例,如果是将 1 压入栈顶,否则将0压入栈顶 |
0xc2 | monitorenter | 获得对象的锁,用于同步方法或同步块 |
0xc3 | monitorexit | 释放对象的锁,用于同步方法或同步块 |
0xc4 | wide | <待补充> |
0xc5 | multianewarray | 创建指定类型和指定维度的多维数组(执行该指令时,操作栈中必须包含各维度的长度值),并将其引用值压入栈顶 |
0xc6 | ifnull | 为 null 时跳转 |
0xc7 | ifnonnull | 不为 null 时跳转 |
0xc8 | goto_w | 无条件跳转(宽索引) |
0xc9 | jsr_w | 跳转至指定 32 位 offset 位置,并将 jsr_w 下一条指令地址压入栈顶 |
3.7. 示例
public void onlyMe(Foo f) {synchronized(f) {doSomething();}
}
编译后,这段代码生成的字节码序列如下:
Method void onlyMe(Foo)
0 aload_1 // 将对象 f 入栈
1 dup // 复制栈顶元素(即 f 的引用)
2 astore_2 // 将栈顶元素存储到局部变量表 Slot 2 中
3 monitorenter // 以栈顶元素(即 f)作为锁,开始同步
4 aload_0 // 将局部变量 Slot 0(即 this 指针)的元素入栈
5 invokevirtual #5 // 调用 doSomething() 方法
8 aload_2 // 将局部变量 Slot 2 的元素(即 f)入栈
9 monitorexit // 退出同步
10 goto 18 // 方法正常结束,跳转到 18 返回
13 astore_3 // 从这步开始是异常路径,见下面异常表的 Target 13
14 aload_2 // 将局部变量 Slot 2 的元素(即 f)入栈
15 monitorexit // 退出同步
16 aload_3 // 将局部变量 Slot 3 的元素(即异常对象)入栈
17 athrow // 把异常对象重新抛出给 onlyMe() 方法的调用者
18 return // 方法正常返回Exception table:
FromTo Target Type4 10 13 any13 16 13 any
相关文章:
JVM 之 字节码指令
目录 一. 前言 二. 指令集 2.1. 支持的数据类型 2.2. 指令分类 三. 指令手册 3.1. 操作数栈 3.2. 运算与转换 3.3. 条件转移 3.4. 类与数组 3.5. 调度与返回加 finally 3.6. 指令手册汇总 3.7. 示例 一. 前言 字节码指令集的特点是数据量短小精干,便于传…...

阿里云跨账号建立局域网
最近有活动,和好友一并薅了下阿里云的羊毛。琢磨着两台机器组一个局域网,于是有了这个需求,把步骤记录一下: 假设两台机器叫A和B,我们开始进行建立和组网 1. 建立ECS 把A机器公共环境装好,然后使用《实例与…...

【OpenSTL】方便好用的时空预测开源库
OpenSTL:方便好用的时空预测开源库 时空预测学习是一种学习范式,它使得模型能够通过在无监督的情况下从给定的过去帧预测未来帧,从而学习空间和时间的模式。尽管近年来取得了显著的进展,但由于不同的设置、复杂的实现和难以复现性…...
【Unity】IBeginDragHandler、IDragHandler 和 IEndDragHandler 介绍
IBeginDragHandler、IDragHandler 和 IEndDragHandler 介绍 IBeginDragHandler、IDragHandler 和 IEndDragHandler 是 Unity 引擎中的三个接口,用于处理 UI 元素的拖放事件。这些接口通常结合使用,构成了 Unity 引擎的拖放事件系统。 IBeginDragHandler…...

杰发科技AC7801——Flash模拟EEP内存分布情况
简介 本文记录了在使用AutoChips芯片Flash模拟EEP过程中的一些理解 核心代码如下 #include <stdlib.h> #include "ac780x_sweeprom.h" #include "ac780x_debugout.h"#define SWEEPROM_SIZE (2048UL) /* Ssoftware eeprom size(Byte) */ #define TE…...
【前端知识】Node——http模块url模块的常用操作
一、创建简易Server const http require(http); const URL require(url);const HTTP_PORT 8088;const server http.createServer((req, res) > {// req:request请求对象,包含请求相关的信息;// res:response响应对象&…...
平衡二叉树 (简单易懂)
目录 一、概念 二、性质 三、插入操作 四、旋转操作 五、删除操作 六、代码实现 七、复杂度 一、概念 平衡二叉树(Balanced Binary Tree)是一种特殊的二叉搜索树(Binary Search Tree,BST),它在插入和…...
Vue.observable 是什么
Observable 翻译过来我们可以理解成可观察的 Vue.js2.6 新增 Vue.observable,让一个对象变成响应式数据。Vue 内部会用它来处理 data 函数返回的对象 。 返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化…...

【五年创作纪念日】
机缘 我成为创作者的过程并不复杂,可以说是一个自然的发展。我是一名软件工程师,日常的工作主要是编程和解决问题。在工作的过程中,我发现有很多时候我需要查找一些特定的技术问题或者寻找一些最佳实践来解决我遇到的问题。在这个过程中&…...
数据库基础入门 — SQL排序与分页
我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 本…...

WordPress站点屏蔽过滤垃圾评论教程(Akismet反垃圾评论插件)
前段时间我的WordPress站点经常收到垃圾评论的轰炸,严重时一天会收到几十条垃圾评论。我这个小破站一没啥流量,二又不盈利,实在是不太理解为啥有人要这么执着地浪费资源在上面。 Akismet反垃圾评论插件 其实用了 Akismet 反垃圾评论插件后&a…...

Modbus-RTU协议讲解与实战
1、背景 工作需要,需要使用Modbus-RTU实现RS485通信,于是简单学习并实践了一下。 2、参考资料 一文看懂Modbus协议 3、协议说明 3.1、协议类型 当前设备采用Modbus-RTU协议,采用CRC-16_Modbus校验算法,数据链路层使用用标准串口协议,物理层采用RS485进行数据传输。 …...
数据结构 查找基本概念
敬请期待。。。 1. 适用于折半查找的表的存储方式及元素排列要求为(顺序方式存储,元素有序 )。 2. 有一个按元素值排好序的顺序表(长度大于2),分别用顺序查找和折半查找与给定值相等的元素,比较次数分别是s和b&am…...

『Linux升级路』基础开发工具——gcc/g++篇
🔥博客主页:小王又困了 📚系列专栏:Linux 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、快速认识gcc/g 二、预处理 📒1.1头文件展开 📒1…...
面试:RocketMQ相关问题
文章目录 什么是 RocketMQ,有哪些使用场景?RocketMQ 由哪些⻆色组成,每个⻆色作用和特点是什么?RocketMQ 中的 Topic 和 JMS 的 queue 有什么区别?RocketMQ 消费模式有几种?RocketMQ 的 Consumer 是如何消费…...

2304. 网格中的最小路径代价 : 从「图论最短路」过渡到「O(1) 空间的原地模拟」
题目描述 这是 LeetCode 上的 「2304. 网格中的最小路径代价」 ,难度为 「中等」。 Tag : 「最短路」、「图」、「模拟」、「序列 DP」、「动态规划」 给你一个下标从 0 开始的整数矩阵 grid,矩阵大小为 m x n,由从 0 到 的不同整数组成。 你…...

【机器学习】算法性能评估常用指标总结
考虑一个二分问题,即将实例分成正类(positive)或负类(negative)。对一个二分问题来说,会出现四种情况。如果一个实例是正类并且也被 预测成正类,即为真正类(True positive࿰…...
前端 JavaScript 与 HTML 怎么实现交互?
前端的交互性是通过JavaScript与HTML结合实现的。JavaScript作为一种脚本语言,可以嵌入HTML中,通过对DOM(文档对象模型)的操作,实现与用户的交互。以下将详细介绍前端JavaScript与HTML如何实现交互,包括事件…...

命令执行总结
之前做了一大堆的题目 都没有进行总结 现在来总结一下命令执行 我遇到的内容 这里我打算按照过滤进行总结 依据我做过的题目 过滤system 下面是一些常见的命令执行内容 system() passthru() exec() shell_exec() popen() proc_open() pcntl_exec() 反引号 同shell_exec() …...
机器学习——词向量模型(CBOW代码实现-未开始)
本来是不打算做这个CBOW代码案例的,想快马加鞭看看前馈神经网络 毕竟书都买好了 可是…可是…我看书的时候,感觉有点儿困难,哭的很大声… 感觉自己脑细胞可能无法这么快接受 要不,还是退而求个稍微难度没那么大的事,想…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...

【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...

RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...

代理服务器-LVS的3种模式与调度算法
作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们上一章介绍了Web服务器,其中以Nginx为主,本章我们来讲解几个代理软件:…...
在ubuntu等linux系统上申请https证书
使用 Certbot 自动申请 安装 Certbot Certbot 是 Let’s Encrypt 官方推荐的自动化工具,支持多种操作系统和服务器环境。 在 Ubuntu/Debian 上: sudo apt update sudo apt install certbot申请证书 纯手动方式(不自动配置)&…...