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.rhkb.cn/news/425380.html

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

相关文章

单硬盘安装Win10和麒麟V10双系统指导建议

随着信创电脑的普及,国产操作系统也逐渐走进了大家的视野,许多人选择了国产操作系统来体验其开源、安全、高效的特性,而Windows系统也是大多数人习惯使用的操作系统。一台电脑上同时安装银河麒麟V10和Windiows10双系统也成为了非常常见的需求。那么,如何在一台电脑上安装银…

外网(公网)访问VMware workstation 虚拟机内web网站的配置方法---端口转发总是不成功的原因

问题背景&#xff1a;客户提供的服务器操作系统配置web程序时&#xff0c;总是显示莫名其妙的问题&#xff0c;发现是高版本操作系统的.net库已经对低版本.net库进行了大范围修订&#xff0c;导致在安全检测上、软件代码规范上更加苛刻&#xff0c;最终导致部署不成功。于是想到…

TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错

目录 1&#xff0c;前言2&#xff0c;二者关系2.1&#xff0c;使用 3&#xff0c;遇到的问题3.1&#xff0c;TS 中使用 JS 1&#xff0c;前言 通过 Vite 创建的 Vue3 TS 项目&#xff0c;根目录下会有 tsconfig.json 和 tsconfig.node.json 文件&#xff0c;并且存在引用关系…

【网络】TCP/IP 五层网络模型:数据链路层

文章目录 认识以太网mac 地址mac 地址和 IP 地址的区别 类型ARP 协议 MTU 日常开发主要是应用层&#xff0c;传输层和应用层密切交互&#xff0c;传输层用到的也不少。网络层以及再往下&#xff0c;日常开发就涉及到的非常少了 认识以太网 插网线的上网方式 80211 是无线 WiF…

指纹与指甲检测系统源码分享

指纹与指甲检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

[网络]TCP/IP协议 之 网络层IP协议(3)

文章目录 一. IP协议报头二. NAT机制三. IP地址管理的基本规则1. 网段划分2. 特殊的IP地址 四. IP路由选择 网络层主要做的事情: 1.路径规划(路由器选择) 2.地址管理 一. IP协议报头 1)4位版本 指定IP协议的版本, 4 > ipv4 , 6 > ipv6 2)4位首部长度 4位bit能表示0-15, …

Linux bash脚本本地开发环境(Git Bash)配置

参考资料 VSCode: Windows 下配置 VSCode运行shellVSCodeを使用したシェルスクリプトの開発環境作成 目录 一. 必备VSCode插件二. 插件配置说明2.1 Bash IDE2.2 Code Runner2.3 shell-format 一. 必备VSCode插件 Bash IDE 该插件为 Bash 脚本提供了一些实用的开发工具和功能&…

如何设置xshell关闭最后一个选项卡标签时不退出软件?

不知道你是否遇到这个问题&#xff0c;就是在使用xshell的时候&#xff0c;每次关闭最后一个选项卡标签的时候&#xff0c;xshell软件默认就退出了&#xff0c;好多次我都只是想要关闭&#xff0c;而非退出&#xff0c;所以该如何设置&#xff0c;才能到我们的预期的效果呢&…

人工智能GPT____豆包使用的一些初步探索步骤 体验不一样的工作

豆包工具是我使用比较频繁的一款软件&#xff0c;其集合了很多功能。对话 图像 AI搜索 伴读等等使用都非常不错。电脑端安装集合了很多功能。 官网直达&#xff1a;豆包 使用我的文案创作能力&#xff0c;您可以注意以下几个技巧&#xff1a; 明确需求&#xff1a; 尽可能具…

云计算和虚拟化技术 背诵

https://zhuanlan.zhihu.com/p/612215164 https://zhuanlan.zhihu.com/p/612215164 云计算是指把计算资源、存储资源、网络资源、应用软件等集合起来&#xff0c;采用虚拟化技术 &#xff0c;将这些资源池化&#xff0c;组成资源共享池&#xff0c;共享池即是“云”。 云计算…

supermap iclient3d for cesium中entity使用

目标将西南石油大学部分区域围起来&#xff0c;然后引个标签显示名称&#xff0c;最后弄个飞机绕学校飞&#xff08;这个时间有点晚了&#xff0c;明天弄) 围墙: wall:{positions:Cesium.Cartesian3.fromDegreesArrayHeights([104.173,30.822,500,104.178,30.837,500,104.19,3…

Qt-QPushButton按钮类控件(22)

目录 描述 使用 给按钮添加图片 给按钮添加快捷键 添加槽函数 添加快捷键 添加组合键 开启鼠标的连发功能 描述 经过上面的一些介绍&#xff0c;我们也尝试的使用过了这个控件&#xff0c;接下来我们就要详细介绍这些比较重要的控件了 使用 给按钮添加图片 我们创建…

局域网windows下使用Git

windows下如何使用局域网进行git部署 准备工作第一步 &#xff0c;ip设置设置远程电脑的ip设置&#xff0c;如果不会设置请点击[这里](https://blog.csdn.net/Black_Friend/article/details/142170705?spm1001.2014.3001.5501)设置本地电脑的ip&#xff1a;验证 第二步&#x…

下载chromedriver驱动

首先进入关于ChromeDriver最新下载地址&#xff1a;Chrome for Testing availability 进入之后找到与自己所匹配的&#xff0c;在浏览器中查看版本号&#xff0c;下载版本号需要一致。 下载即可&#xff0c;解压&#xff0c;找到 直接放在pycharm下即可 因为在环境变量中早已配…

两个人群填充参考(CHN100K和NARD)

分别是中国人群和东北亚人群的填充参考&#xff0c;测试了下&#xff0c;中国人群的参考注册还是相对友好的&#xff0c;没有像有些网站一样严格限制。东北亚的没有测试&#xff0c;两个数据库的特点都是包含了少数民族&#xff0c;研究朝鲜或蒙古族或其他民族的同学&#xff0…

9.12 TFTP通信

客户端设计&#xff08;仅供参考&#xff09;&#xff1a; 下载本质&#xff1a;读取服务器发送的数据包&#xff0c;写入到本地文件 上传本质&#xff1a;读取本地文件内容&#xff0c;发送给服务器。 1、建立菜单选项&#xff0c;上传和下载。 2、上传功能函数&#xff1a; …

java开发中间件学习记录(持续更新中~)

1 Redis 2JVM 3 java基础底层 4Mysql 5 spring 6 微服务 7.......(持续更新) One:Redis篇 1:Redis 1.穿透 1.1缓存穿透 1.1.1布隆过滤器 1.2缓存击穿 2&#xff1a;击穿 1.3&#xff1a;缓存雪崩 1.4:双写一致 1.5.持久化&#xff08;RDB,AOF&#xff09; 1.6…

深入浅出Docker

1. Docker引擎 Docker引擎是用来运行和管理容器的核心软件。通常人们会简单的将其指代为Docker或Docker平台。 基于开放容器计划&#xff08;OCI&#xff09;相关的标准要求&#xff0c;Docker引擎采用了模块化的设计原则&#xff0c;其组件是可替换的。 Docker引擎由如下主…

k8s中的存储

目录 一 configmap 1.1 configmap的功能 1.2 configmap的使用场景 1.3 configmap创建方式 1.3.1 字面值创建 1.3.2 通过文件创建 1.3.3 通过目录创建 1.3.4 通过yaml文件创建 1.3.5 configmap的使用方式 1.3.5.1 使用configmap填充环境变量 1.3.5.2 通过数据卷使用c…

YOLOv10改进系列,YOLOv10颈部网络SPPF替换为FocalModulation

摘要 焦点调制网络(简称FocalNets),其中自注意力(SA)完全由焦点调制模块取代,用于在视觉中建模标记交互。焦点调制包括三个组件:(i)焦点情境化,通过一堆深度卷积层实现,从短到长范围编码视觉上下文,(ii)门控聚合,选择性地将上下文聚集到每个查询标记的调制器中…