JVM字节码与局部变量表

文章目录

  • 局部变量表
  • javap
  • 字节码
    • 指令分类
  • 指令
    • 指令数据类型前缀
    • 加载和存储指令
    • 加载常量
    • 算术指令
    • 其他指令
  • 字节码示例说明

局部变量表

每个线程的帧栈是独立的,每个线程中的方法调用会产生栈帧,栈帧中保存着方法执行的信息,例如局部变量表。

局部变量表是一个数组,大小在编译时就确定了,方法运行期间是不会改变局部变量表的大小。

局部变量表是一个数组中保存的结构叫做:slot

slot中的变量类型有下面10种(8种基本类型、引用类型、返回地址):

  1. byte
  2. bool
  3. char
  4. short
  5. int
  6. flot
  7. double
  8. long
  9. reference(引用类型)
  10. returnAddress(返回值地址)

除了long和double会占用2个slot,其他类型占用1个slot,byte、short、char、bool类型会转换为int类型存储。
局部变量表

JVM会为局部变量表中的每一个slot都分配一个访问索引,通过索引访问到局部变量表中指定的局部变量值。

索引从0开始,如果当前帧是由构造方法或者实例方法创建,那么该对象引用this会被存储在索引为0的slot。

当一个实例方法被调用的时候,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个slot上。

局slot可以重用,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就可以复用过期局部变量的slot。

局部变量表不存在系统初始化的过程,所以定义局部变量必须手动初始化,这个编译时就能检查。

只要被局部变量表中直接或间接引用的对象都不会被回收。

javap

javap主要用来做反编译,可以查看编译之后的字节码,可以看javac处理之后的代码是什么样。

通过字节码可以看出:做了哪些优化,处理了哪些语法糖。

最常见3个参数:

  1. -c:查看反编译方法
  2. -l(小写L):-c的基础上多了局部变量表、指令索引和源码行号的对应关系
  3. -v: 所有信息
参数作用说明
-version版本信息
-v 或 -verbose输出附加信息
-l输出行号和局部变量表
-public仅显示公共类和成员
-protected显示受保护的/公共类和成员
-package显示程序包/受保护的/公共类和成员
-p 或 -private显示所有类和成员
-c对代码进行反汇编
-s输出简洁版,只包含方法签名等基本信息
-sysinfo显示正在处理的类的系统信息
-constants显示最终常量
-classpath path指定查找用户类文件的位置
-cp path指定查找用户类文件的位置
-bootclasspath path覆盖引导类文件的位置

字节码

字节码执行有一个操作栈,后面说的放入栈顶就是指操作栈顶。

指令分类

  1. 加载指令(Load):用于把变量从主存加载到栈内存
  2. 存储指令(Store):用于把变量从栈内存存储到主存
  3. 栈操作指令(Stack):用于对栈进行操作,比如交换栈顶元素,复制栈顶元素等
  4. 算术指令(Arithmetic):用于进行算术运算,比如加法,减法,乘法,除法等
  5. 转换指令(Conversion):用于进行类型转换,比如将int类型转为float类型等
  6. 比较指令(Comparison):用于进行数值比较
  7. 控制指令(Control):用于进行控制流转移
  8. 引用指令(Reference):用于操作对象,比如创建对象,获取对象的字段等
  9. 扩展指令(Extended):用于对指令集进行扩展
  10. 同步指令(Synchronization):用于线程同步

指令

指令说明
load加载操作,通常表示从局部变量表或数组中加载一个值到操作数栈
store存储操作,通常表示将一个值从操作数栈存储到局部变量表或数组中
add加运算
sub减运算
mul乘运算
div除运算
rem取余运算
and位与运算
or位或运算
xor异或运算
neg取反操作
shl左移操作
shr有符号右移
ushr无符号右移操作
cmpeq等于
cmpne不等于
cmplt小于
cmpge大于等于
cmpgt大于
cmple小于等于
const用于表示将常量加载到操作数栈
length表示获取数组的长度
goto表示无条件跳转
if表示条件跳转
return表示从方法返回
invoke表示调用方法

指令数据类型前缀

字节码指令通常以一个字符作为前缀,表示操作数的类型。

指令前缀代表数据类型
i表示操作数是int类型
l表示操作数是long类型
f表示操作数是float类型
d表示操作数是double类型
a表示操作数是对象引用类型
b表示操作数是byte类型
c表示操作数是char类型
s表示操作数是short类型

例如:iload表示加载一个int类型的局部变量,fadd表示将两个float类型的值相加。

加载和存储指令

xload_n:局部变量表加载到操作栈
xstore_n:操作栈数据存储到局部变量表

x:可以是i(int、byte、char、short、boolean类型)、l(long类型)、f(float类型)、d(double类型)、a(引用类型)
n:[0,3]

指令描述
aload_0将局部变量表中索引为0的slot的引用数据类型数据加载到操作栈顶
iload_1将局部变量表中索引为1的slot的int类型数据加载到操作栈顶
lload_2将局部变量表中索引为2的slot的long类型数据加载到操作栈顶
fload_3将局部变量表中索引为3的slot的float类型数据加载到操作栈顶
astore_0将操作栈顶引用类型数值存入局部变量表中第0个索引的slot中
istore_1将操作栈顶int类型数据存入局部变量表中第1个索引的slot中
dstore_2将操作栈顶double类型数据存入局部变量表中第2个索引的slot中
lstore_3将操作栈顶long类型数据存入局部变量表中第3个索引的slot中

有善于思考的朋友可能就要问了:局部变量表大于4个怎么办呢?

使用:

  1. xload arg:例如 iload 4 表示将局部变量表中索引为4的slot放入栈顶
  2. xstore arg:例如 istore 4表示将栈顶元素放入局部变量表中索引为4的slot

x:可以是i(int、byte、char、short、boolean类型)、l(long类型)、f(float类型)、d(double类型)、a(引用类型)

加载常量

指令含义
aconst_null将null对象引用压入栈
iconst_m1将int类型常量-1压入栈
iconst_0将int类型常量0压入栈
iconst_1将int类型常量1压入栈
iconst_2将int类型常量2压入栈
iconst_3将int类型常量3压入栈
iconst_4将int类型常量4压入栈
iconst_5将int类型常量5压入栈
lconst_0将long类型常量0压入栈
lconst_1将long类型常量1压入栈
fconst_0将float类型常量0压入栈
fconst_1将float类型常量1压入栈
dconst_0将double类型常量0压入栈
dconst_1将double类型常量1压入栈
bipush将一个byte[-128,127]常量压入栈
sipush将short[-32768,32767]常量压入栈
ldcint, float或String型常量值压入栈
ldc_w将int, float或String型常量值压入栈
ldc2_w将long、double常量值从常量池压入栈

如果int常量大于6个怎么整呢?

答案是:

  1. 小于127使用bipush x,例如:bipush 127
  2. 大于127小于等于32767使用sipush x,例如:sipush 32767
  3. 大于32767使用ldc x(常量引用),例如:ldc #31

算术指令

指令描述
iadd将栈顶两int类型数值相加并将结果压入栈顶
ladd将栈顶两long类型数值相加并将结果压入栈顶
fadd将栈顶两float类型数值相加并将结果压入栈顶
dadd将栈顶两double类型数值相加并将结果压入栈顶
isub将栈顶两int类型数值相减并将结果压入栈顶
lsub将栈顶两long类型数值相减并将结果压入栈顶
fsub将栈顶两float类型数值相减并将结果压入栈顶
dsub将栈顶两double类型数值相减并将结果压入栈顶
imul将栈顶两int类型数值相乘并将结果压入栈顶
lmul将栈顶两long类型数值相乘并将结果压入栈顶
fmul将栈顶两float类型数值相乘并将结果压入栈顶
dmul将栈顶两double类型数值相乘并将结果压入栈顶
idiv将栈顶两int类型数值相除并将结果压入栈顶
ldiv将栈顶两long类型数值相除并将结果压入栈顶
fdiv将栈顶两float类型数值相除并将结果压入栈顶
ddiv将栈顶两double类型数值相除并将结果压入栈顶

其他指令

指令描述
i2l将栈顶int类型数值转换为long类型并压入栈顶
i2f将栈顶int类型数值转换为float类型并压入栈顶
i2d将栈顶int类型数值转换为double类型并压入栈顶
new创建一个对象,并将引用值压入栈顶
anewarray创建一个引用类型数组,并将引用值压入栈顶
arraylength获取数组的长度值,并将长度值压入栈顶
pop弹出栈顶数值
pop2弹出栈顶的一个或两个数值
dup复制栈顶数值并压入栈顶
ifeq当栈顶int类型数值等于0时跳转
ifne当栈顶int类型数值不等于0时跳转
goto无条件跳转
invokevirtual调用实例方法
invokespecial调用构造函数,私有方法和父类方法
invokestatic调用静态方法
return从当前方法返回void
athrow将栈顶的异常抛出
monitorenter获取对象的锁
monitorexit释放对象的锁
putfield将栈顶的一个值存储到对象的字段中
getfield从对象中取出一个字段的值

字节码示例说明

局部变量与字节码

示例类:

public class ByteCodeMain {public static final String HELLO = "HELLO";private Integer score;private String name;public ByteCodeMain(Integer score, String name) {this.score = score;this.name = name;}public int addScore(int add) {return this.score + doubleNum(add);}private static int doubleNum(int add){return add * 2;}public String sayHello(String append) {return HELLO + " " + this.name + append;}public Integer getScore() {return score;}public String getName() {return name;}public static void main(String[] args) {ByteCodeMain byteCodeMain = new ByteCodeMain(10, "Allen");System.out.println(byteCodeMain.getName());System.out.println(byteCodeMain.getScore());int resultNum = byteCodeMain.addScore(20);System.out.println(resultNum);String resultStr = byteCodeMain.sayHello(" 你好啊!");System.out.println(resultStr);System.out.println("常量:" + HELLO);}
}

编译获取class文件,然后使用javap反编译:

javac ByteCodeMain.java
javap -v ByteCodeMain.class

获取到如下的字节码

Classfile ByteCodeMain.classLast modified ; size 2259 bytesSHA-256 checksum 7f96af8a9fec8835a0615c774629e0fcad2e6f00c7afaa33a88eb72cc834fd8fCompiled from "ByteCodeMain.java"
public class vip.meet.base.bytecode.ByteCodeMainminor version: 0major version: 61 // JDK17flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #8                          // vip/meet/base/bytecode/ByteCodeMainsuper_class: #2                         // java/lang/Objectinterfaces: 0, fields: 3, methods: 7, attributes: 3
Constant pool: // 常量池#1 = Methodref          #2.#3         // java/lang/Object."<init>":()V#2 = Class              #4            // java/lang/Object#3 = NameAndType        #5:#6         // "<init>":()V#4 = Utf8               java/lang/Object#5 = Utf8               <init>#6 = Utf8               ()V#7 = Fieldref           #8.#9         // vip/meet/base/bytecode/ByteCodeMain.score:Ljava/lang/Integer;#8 = Class              #10           // vip/meet/base/bytecode/ByteCodeMain#9 = NameAndType        #11:#12       // score:Ljava/lang/Integer;#10 = Utf8               vip/meet/base/bytecode/ByteCodeMain#11 = Utf8               score#12 = Utf8               Ljava/lang/Integer;#13 = Fieldref           #8.#14        // vip/meet/base/bytecode/ByteCodeMain.name:Ljava/lang/String;#14 = NameAndType        #15:#16       // name:Ljava/lang/String;#15 = Utf8               name#16 = Utf8               Ljava/lang/String;#17 = Methodref          #18.#19       // java/lang/Integer.intValue:()I#18 = Class              #20           // java/lang/Integer#19 = NameAndType        #21:#22       // intValue:()I#20 = Utf8               java/lang/Integer#21 = Utf8               intValue#22 = Utf8               ()I#23 = Methodref          #8.#24        // vip/meet/base/bytecode/ByteCodeMain.doubleNum:(I)I#24 = NameAndType        #25:#26       // doubleNum:(I)I#25 = Utf8               doubleNum#26 = Utf8               (I)I#27 = InvokeDynamic      #0:#28        // #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#28 = NameAndType        #29:#30       // makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#29 = Utf8               makeConcatWithConstants#30 = Utf8               (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#31 = Methodref          #18.#32       // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#32 = NameAndType        #33:#34       // valueOf:(I)Ljava/lang/Integer;#33 = Utf8               valueOf#34 = Utf8               (I)Ljava/lang/Integer;#35 = String             #36           // Allen#36 = Utf8               Allen#37 = Methodref          #8.#38        // vip/meet/base/bytecode/ByteCodeMain."<init>":(Ljava/lang/Integer;Ljava/lang/String;)V#38 = NameAndType        #5:#39        // "<init>":(Ljava/lang/Integer;Ljava/lang/String;)V#39 = Utf8               (Ljava/lang/Integer;Ljava/lang/String;)V#40 = Fieldref           #41.#42       // java/lang/System.out:Ljava/io/PrintStream;#41 = Class              #43           // java/lang/System#42 = NameAndType        #44:#45       // out:Ljava/io/PrintStream;#43 = Utf8               java/lang/System#44 = Utf8               out#45 = Utf8               Ljava/io/PrintStream;#46 = Methodref          #8.#47        // vip/meet/base/bytecode/ByteCodeMain.getName:()Ljava/lang/String;#47 = NameAndType        #48:#49       // getName:()Ljava/lang/String;#48 = Utf8               getName#49 = Utf8               ()Ljava/lang/String;#50 = Methodref          #51.#52       // java/io/PrintStream.println:(Ljava/lang/String;)V#51 = Class              #53           // java/io/PrintStream#52 = NameAndType        #54:#55       // println:(Ljava/lang/String;)V#53 = Utf8               java/io/PrintStream#54 = Utf8               println#55 = Utf8               (Ljava/lang/String;)V#56 = Methodref          #8.#57        // vip/meet/base/bytecode/ByteCodeMain.getScore:()Ljava/lang/Integer;#57 = NameAndType        #58:#59       // getScore:()Ljava/lang/Integer;#58 = Utf8               getScore#59 = Utf8               ()Ljava/lang/Integer;#60 = Methodref          #51.#61       // java/io/PrintStream.println:(Ljava/lang/Object;)V#61 = NameAndType        #54:#62       // println:(Ljava/lang/Object;)V#62 = Utf8               (Ljava/lang/Object;)V#63 = Methodref          #8.#64        // vip/meet/base/bytecode/ByteCodeMain.addScore:(I)I#64 = NameAndType        #65:#26       // addScore:(I)I#65 = Utf8               addScore#66 = Methodref          #51.#67       // java/io/PrintStream.println:(I)V#67 = NameAndType        #54:#68       // println:(I)V#68 = Utf8               (I)V#69 = String             #70           //  你好啊!#70 = Utf8                你好啊!#71 = Methodref          #8.#72        // vip/meet/base/bytecode/ByteCodeMain.sayHello:(Ljava/lang/String;)Ljava/lang/String;#72 = NameAndType        #73:#74       // sayHello:(Ljava/lang/String;)Ljava/lang/String;#73 = Utf8               sayHello#74 = Utf8               (Ljava/lang/String;)Ljava/lang/String;#75 = String             #76           // 常量:HELLO#76 = Utf8               常量:HELLO#77 = Utf8               HELLO#78 = Utf8               ConstantValue#79 = String             #77           // HELLO#80 = Utf8               Code#81 = Utf8               LineNumberTable#82 = Utf8               LocalVariableTable#83 = Utf8               this#84 = Utf8               Lvip/meet/base/bytecode/ByteCodeMain;#85 = Utf8               MethodParameters#86 = Utf8               add#87 = Utf8               I#88 = Utf8               append#89 = Utf8               main#90 = Utf8               ([Ljava/lang/String;)V#91 = Utf8               args#92 = Utf8               [Ljava/lang/String;#93 = Utf8               byteCodeMain#94 = Utf8               resultNum#95 = Utf8               resultStr#96 = Utf8               SourceFile#97 = Utf8               ByteCodeMain.java#98 = Utf8               BootstrapMethods#99 = String             #100          // HELLO \u0001\u0001#100 = Utf8               HELLO \u0001\u0001#101 = MethodHandle       6:#102        // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#102 = Methodref          #103.#104     // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#103 = Class              #105          // java/lang/invoke/StringConcatFactory#104 = NameAndType        #29:#106      // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#105 = Utf8               java/lang/invoke/StringConcatFactory#106 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#107 = Utf8               InnerClasses#108 = Class              #109          // java/lang/invoke/MethodHandles$Lookup#109 = Utf8               java/lang/invoke/MethodHandles$Lookup#110 = Class              #111          // java/lang/invoke/MethodHandles#111 = Utf8               java/lang/invoke/MethodHandles#112 = Utf8               Lookup
{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String HELLOpublic vip.meet.base.bytecode.ByteCodeMain(java.lang.Integer, java.lang.String);descriptor: (Ljava/lang/Integer;Ljava/lang/String;)V // 构造函数flags: (0x0001) ACC_PUBLICCode:stack=2, locals=3, args_size=30: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this1: invokespecial #1                  // 调用Object的构造函数,Method java/lang/Object."<init>":()V4: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this5: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,Integer(score)6: putfield      #7                  // 将栈顶元素score设置到对象变量,Field score:Ljava/lang/Integer;9: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this10: aload_2 // 加载局部变量表索引为2的slot数据到栈顶,String(name)11: putfield      #13                 // 将栈顶元素name设置到对象变量,Field name:Ljava/lang/String;14: returnLineNumberTable:line 13: 0line 14: 4line 15: 9line 16: 14LocalVariableTable: // 局部变量表Start  Length  Slot  Name   Signature0      15     0  this   Lvip/meet/base/bytecode/ByteCodeMain;0      15     1 score   Ljava/lang/Integer;0      15     2  name   Ljava/lang/String;MethodParameters:Name                           Flagsscorenamepublic int addScore(int);descriptor: (I)Iflags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this1: getfield      #7                  // 获取对象变量放入栈顶,Field score:Ljava/lang/Integer;4: invokevirtual #17                 // 调用对象方法(将int转为Integer对象),Method java/lang/Integer.intValue:()I7: iload_1 // 加载局部变量表索引为1的slot数据到栈顶,add8: invokestatic  #23                 // 调用静态方法,Method doubleNum:(I)I11: iadd // 将栈顶2元素相加之和放入栈顶12: ireturn // 返回int类型LineNumberTable:line 19: 0LocalVariableTable:Start  Length  Slot  Name   Signature0      13     0  this   Lvip/meet/base/bytecode/ByteCodeMain;0      13     1   add   IMethodParameters:Name                           Flagsaddpublic java.lang.String sayHello(java.lang.String);descriptor: (Ljava/lang/String;)Ljava/lang/String;flags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this1: getfield      #13                 // 获取对象变量放入栈顶,Field name:Ljava/lang/String;4: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,append5: invokedynamic #27,  0             // 调用动态方法,InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;10: areturnLineNumberTable:line 27: 0LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   Lvip/meet/base/bytecode/ByteCodeMain;0      11     1 append   Ljava/lang/String;MethodParameters:Name                           Flagsappendpublic java.lang.Integer getScore();descriptor: ()Ljava/lang/Integer;flags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield      #7                  // Field score:Ljava/lang/Integer;4: areturnLineNumberTable:line 31: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lvip/meet/base/bytecode/ByteCodeMain;public java.lang.String getName();descriptor: ()Ljava/lang/String;flags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield      #13                 // Field name:Ljava/lang/String;4: areturnLineNumberTable:line 35: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lvip/meet/base/bytecode/ByteCodeMain;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=4, locals=4, args_size=10: new           #8                  // 创建ByteCodeMain对象,并放入栈顶,class vip/meet/base/bytecode/ByteCodeMain3: dup // 复制栈顶元素并压入栈顶4: bipush        10 // 将byte类型常量10压入栈顶,字面量常量10被处理成了一个字节的byte类型6: invokestatic  #31                 // 调用静态方法,Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: ldc           #35                 // 将常量池#35常量放入栈顶,String Allen11: invokespecial #37                 // 调用构造方法,Method "<init>":(Ljava/lang/Integer;Ljava/lang/String;)V14: astore_1 // 将栈顶元素(上一步构建的ByteCodeMain对象)放入局部变量表索引为1的slot15: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;18: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,ByteCodeMain对象19: invokevirtual #46                 // 调用实例方法,Method getName:()Ljava/lang/String;22: invokevirtual #50                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V25: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;28: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,ByteCodeMain对象29: invokevirtual #56                 // 调用实例方法,Method getScore:()Ljava/lang/Integer;32: invokevirtual #60                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/Object;)V35: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,ByteCodeMain对象36: bipush        20 // 将byte类型常量20压入栈顶,字面量常量20被处理成了一个字节的byte类型38: invokevirtual #63                 // 调用实例方法,Method addScore:(I)I41: istore_2 // 将栈顶元素(上一步addScore计算获得的值)放入局部变量表索引为2的slot42: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;45: iload_2 // 加载局部变量表索引为2的slot数据到栈顶,resultNum46: invokevirtual #66                 // 调用实例方法,Method java/io/PrintStream.println:(I)V49: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,ByteCodeMain对象50: ldc           #69                 // 将常量池#69常量放入栈顶,String  你好啊!52: invokevirtual #71                 // 调用实例方法,Method sayHello:(Ljava/lang/String;)Ljava/lang/String;55: astore_3 // 将栈顶元素(sayHello方法返回值)放入局部变量表索引为3的slot,resultStr56: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;59: aload_3 // 加载局部变量表索引为3的slot数据到栈顶,resultStr60: invokevirtual #50                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V63: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;66: ldc           #75                 // 将常量池#75常量放入栈顶,String 常量:HELLO68: invokevirtual #50                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V71: returnLineNumberTable:line 39: 0line 40: 15line 41: 25line 42: 35line 43: 42line 44: 49line 45: 56line 46: 63line 47: 71LocalVariableTable:Start  Length  Slot  Name   Signature0      72     0  args   [Ljava/lang/String;15      57     1 byteCodeMain   Lvip/meet/base/bytecode/ByteCodeMain;42      30     2 resultNum   I56      16     3 resultStr   Ljava/lang/String;MethodParameters:Name                           Flagsargs
}
SourceFile: "ByteCodeMain.java"
BootstrapMethods:0: #101 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;Method arguments:#99 HELLO \u0001\u0001
InnerClasses:public static final #112= #108 of #110; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles

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

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

相关文章

防火墙配置变更管理

在任何组织中&#xff0c;当涉及到网络安全时&#xff0c;频繁地更换防火墙是必要的&#xff0c;实施简化的防火墙更改管理策略模板可以减少管理时间&#xff0c;还可以减少每次变更引入新的安全性或合规性问题的可能性。典型的防火墙变更管理流程将包括以下步骤&#xff1a; …

八股文-多线程、并发

八股文-多线程、并发 最近学到了一种方法&#xff0c;可以用于简历项目经验编写以及面试题目的回答 STAR法则&#xff1a;在什么背景下&#xff0c;你需要解决什么问题&#xff0c;你做了啥&#xff0c;得到了什么结果 情境&#xff08;Situation&#xff09;&#xff1a; 描…

无人机维修保养一对一教学技术详解

随着无人机技术的日益普及和应用的广泛深入&#xff0c;无人机的维修保养成为确保飞行安全、延长使用寿命的关键环节。为了培养专业的无人机维护人才&#xff0c;一对一教学成为了一种高效、针对性的培训方式。以下将详细解析无人机维修保养一对一教学的技术要点&#xff0c;涵…

QT Layout布局,隐藏其中的某些部件后,不影响原来的布局

最近在工作时&#xff0c;被要求&#xff0c;需要将布局中的某些部件隐藏后&#xff0c;但不能影响原来的布局。 现在记录解决方案&#xff01; 一、水平布局&#xff08;垂直布局一样&#xff09; ui中的布局 效果&#xff1a; 按钮可以任意隐藏&#xff0c;都不影响其中布…

Ceph 基本架构(一)

Ceph架构图 Ceph整体组成 Ceph 是一个开源的分布式存储系统&#xff0c;设计用于提供优秀的性能、可靠性和可扩展性。Ceph 的架构主要由几个核心组件构成&#xff0c;每个组件都有特定的功能&#xff0c;共同协作以实现高可用性和数据的一致性。 以下是 Ceph 的整体架构及其…

Pikachu靶场之XSS

先来点鸡汤&#xff0c;少就是多&#xff0c;慢就是快。 环境搭建 攻击机kali 192.168.146.140 靶机win7 192.168.146.161 下载zip&#xff0c;pikachu - GitCode 把下载好的pikachu-master&#xff0c;拖进win7&#xff0c;用phpstudy打开网站根目录&#xff0c;.....再用…

CleanMyMac 5 for Mac 最新中文破解版下载 系统优化垃圾清理工具

今天给大家带来的是CleanMyMac最新款CleanMyMac 5&#xff0c;它是一个全面的Mac清理和维护工具&#xff0c;通过提供多项强大的功能&#xff0c;帮助用户简化日常维护任务&#xff0c;提升系统性能&#xff0c;同时保护个人隐私和安全。无论是新手还是经验丰富的Mac用户&#…

京东广告投放平台整洁架构演进之路

作者&#xff1a;广告研发 赵嘉铎 前言 从去年开始京东广告投放系统做了一次以领域驱动设计为思想内核的架构升级&#xff0c;在深入理解DDD思想的同时&#xff0c;我们基于广告投放业务的本质特征大胆地融入了自己的理解和改造。新架构是从设计思想到落地框架都进行了彻底的…

Python 解析 Charles JSON Session File (.chlsj)

Charles 代理&#xff0c;是一款抓包软件&#xff0c;可以帮助我们抓取浏览器请求跟响应。 1、在 Filter 里面输入需要抓包的网址 2、右键 Export Session 3、文件类型选择 JSON Session File (.chlsj) 保存 4、解析响应的数据结构 response.body.text 是文本字符串。 # 导入…

自然语言处理-基于注意力机制的文本匹配

背景&#xff1a; 任务三&#xff1a;基于注意力机制的文本匹配 输入两个句子判断&#xff0c;判断它们之间的关系。参考ESIM&#xff08;可以只用LSTM&#xff0c;忽略Tree-LSTM&#xff09;&#xff0c;用双向的注意力机制实现。 参考 《神经网络与深度学习》 第7章 Reaso…

SpringCloud微服务消息驱动的实践指南

Spring Cloud是一个用于构建分布式系统的开发工具&#xff0c;通过它可以快速搭建基于微服务架构的应用&#xff0c;并提供了丰富的功能和解决方案。在Spring Cloud中&#xff0c;消息驱动是一种常见的通信模式&#xff0c;通过消息传递来实现不同微服务之间的数据交互。本文将…

【移动端开发】“明日头条APP”

文章目录 1 系统概述1.1研究背景1.2研究意义 2 系统设计2.1 关键技术2.2 系统设计2.2.1 系统功能模块2.2.2 数据库设计 3 系统实现3.1 数据模型3.1.1 NewsURL3.1.2 NewsType3.1.3 NewsInfo 3.2 数据库操作3.2.1 DBOpenHelper3.2.2 DBManager 3.3 适配器类3.3.1 AddItem3.3.2 In…

LabVIEW机械产品几何精度质检系统

随着制造业的发展&#xff0c;对产品质量的要求越来越高&#xff0c;机械产品的几何精度成为衡量其品质的重要指标。为了提高检测效率和精度&#xff0c;开发了一套基于LabVIEW的几何精度质检系统&#xff0c;该系统不仅可以自动化地进行几何尺寸的测量&#xff0c;而且能实时分…

Qt 边框border - qss样式

border属性 实际上&#xff0c;border并不是一个单独的属性&#xff0c;在Qt样式表中&#xff0c;它通常指的是一系列与边框相关的属性的组合。然而&#xff0c;你也可以在一条样式规则中一次性设置所有这些值&#xff0c;如下所示&#xff1a; QPushButton { border: 2px sol…

smardaten无代码这么牛逼?逻辑编排不用代码!

目录 前言 经典案例 ①计划编排&#xff1a;数据操作自动化 ②工单派工&#xff1a;流程变更自动化 smardaten能力解析 一、逻辑控制篇 &#xff08;1&#xff09;变量定义与操作 &#xff08;2&#xff09;数据校验与反馈 &#xff08;3&#xff09;动态数据获取与回填…

演示:基于WPF自绘的中国省份、城市、区县矢量地图

一、目的&#xff1a;演示一个基于WPF自绘的中国省份、城市、区县矢量地图 二、效果 国 省 市 三、功能 支持实际经纬度显示 支持平移&#xff0c;缩放等功能 显示中国地图 显示各个省份地图 显示各个省份地图&#xff08;包含在表格中&#xff0c;包含缩率图&#xff09; 显…

Android Studio报错: Could not find pub.devrel:easypermissions:0.3.0, 改用linux编译

在Android studio中去编译开源的仓库&#xff0c;大概率就是各种编译不过&#xff0c;一堆错误&#xff0c;一顿改错&#xff0c;基本上会耗费非常多时间&#xff0c;比如&#xff1a; 这个就是改gradle版本&#xff0c;改成7.2 &#xff0c;修改完成之后&#xff0c;还有其他报…

rabbitmq容器化部署

目录 需求 容器化部署rabbitmq服务 部署服务 验证及访问服务 rabbitmq配置LTS 服务验证 rabbitmq配置集群 部署集群 1、创建一个存放配置文件的目录 2、创建配置文件 3、部署各个节点 集群验证 需求 容器化部署rabbitmq服务 基础版本 系统ubuntu 24&#xff0c;docke…

Java后端框架---Spring

目录 一.Spring是什么&#xff1f; 二.Spring Hello World 搭建 三.XML配置bean管理 1.bean标签 2.依赖注入 3.依赖注入的补充 四.注解配置bean管理 1.开启注解扫描 2.使用注解对类进行配置 3.自动注入 五.面向切面编程AOP 1.概述 2.通知 六.spring事务管理 1.数据库…

【踩坑】装了显卡,如何让显示器从主板和显卡HDMI都输出

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 背景介绍 装了显卡后&#xff0c;开机默认是从显卡的HDMI输出&#xff0c;但这很不方便。如何让视频仍然从主板输出&#xff1f;或者说让显卡HDMI和主板…