JVM字节码与局部变量表

news2024/11/17 1:33:52

文章目录

  • 局部变量表
  • 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.class
  Last modified ; size 2259 bytes
  SHA-256 checksum 7f96af8a9fec8835a0615c774629e0fcad2e6f00c7afaa33a88eb72cc834fd8f
  Compiled from "ByteCodeMain.java"
public class vip.meet.base.bytecode.ByteCodeMain
  minor version: 0
  major version: 61 // JDK17
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #8                          // vip/meet/base/bytecode/ByteCodeMain
  super_class: #2                         // java/lang/Object
  interfaces: 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_FINAL
    ConstantValue: String HELLO

  public vip.meet.base.bytecode.ByteCodeMain(java.lang.Integer, java.lang.String);
    descriptor: (Ljava/lang/Integer;Ljava/lang/String;)V // 构造函数
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=3
         0: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this
         1: invokespecial #1                  // 调用Object的构造函数,Method java/lang/Object."<init>":()V
         4: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this
         5: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,Integer(score)
         6: putfield      #7                  // 将栈顶元素score设置到对象变量,Field score:Ljava/lang/Integer;
         9: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this
        10: aload_2 // 加载局部变量表索引为2的slot数据到栈顶,String(name)
        11: putfield      #13                 // 将栈顶元素name设置到对象变量,Field name:Ljava/lang/String;
        14: return
      LineNumberTable:
        line 13: 0
        line 14: 4
        line 15: 9
        line 16: 14
      LocalVariableTable: // 局部变量表
        Start  Length  Slot  Name   Signature
            0      15     0  this   Lvip/meet/base/bytecode/ByteCodeMain;
            0      15     1 score   Ljava/lang/Integer;
            0      15     2  name   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      score
      name

  public int addScore(int);
    descriptor: (I)I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this
         1: getfield      #7                  // 获取对象变量放入栈顶,Field score:Ljava/lang/Integer;
         4: invokevirtual #17                 // 调用对象方法(将int转为Integer对象),Method java/lang/Integer.intValue:()I
         7: iload_1 // 加载局部变量表索引为1的slot数据到栈顶,add
         8: invokestatic  #23                 // 调用静态方法,Method doubleNum:(I)I
        11: iadd // 将栈顶2元素相加之和放入栈顶
        12: ireturn // 返回int类型
      LineNumberTable:
        line 19: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   Lvip/meet/base/bytecode/ByteCodeMain;
            0      13     1   add   I
    MethodParameters:
      Name                           Flags
      add

  public java.lang.String sayHello(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0 // 加载局部变量表索引为0的slot数据到栈顶,this
         1: getfield      #13                 // 获取对象变量放入栈顶,Field name:Ljava/lang/String;
         4: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,append
         5: invokedynamic #27,  0             // 调用动态方法,InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
        10: areturn
      LineNumberTable:
        line 27: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Lvip/meet/base/bytecode/ByteCodeMain;
            0      11     1 append   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      append

  public java.lang.Integer getScore();
    descriptor: ()Ljava/lang/Integer;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field score:Ljava/lang/Integer;
         4: areturn
      LineNumberTable:
        line 31: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lvip/meet/base/bytecode/ByteCodeMain;

  public java.lang.String getName();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #13                 // Field name:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 35: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lvip/meet/base/bytecode/ByteCodeMain;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=1
         0: new           #8                  // 创建ByteCodeMain对象,并放入栈顶,class vip/meet/base/bytecode/ByteCodeMain
         3: 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 Allen
        11: invokespecial #37                 // 调用构造方法,Method "<init>":(Ljava/lang/Integer;Ljava/lang/String;)V
        14: astore_1 // 将栈顶元素(上一步构建的ByteCodeMain对象)放入局部变量表索引为1的slot
        15: 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;)V
        25: 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;)V
        35: aload_1 // 加载局部变量表索引为1的slot数据到栈顶,ByteCodeMain对象
        36: bipush        20 // 将byte类型常量20压入栈顶,字面量常量20被处理成了一个字节的byte类型
        38: invokevirtual #63                 // 调用实例方法,Method addScore:(I)I
        41: istore_2 // 将栈顶元素(上一步addScore计算获得的值)放入局部变量表索引为2的slot
        42: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;
        45: iload_2 // 加载局部变量表索引为2的slot数据到栈顶,resultNum
        46: invokevirtual #66                 // 调用实例方法,Method java/io/PrintStream.println:(I)V
        49: 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,resultStr
        56: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;
        59: aload_3 // 加载局部变量表索引为3的slot数据到栈顶,resultStr
        60: invokevirtual #50                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V
        63: getstatic     #40                 // 获取静态变量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;
        66: ldc           #75                 // 将常量池#75常量放入栈顶,String 常量:HELLO
        68: invokevirtual #50                 // 调用实例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V
        71: return
      LineNumberTable:
        line 39: 0
        line 40: 15
        line 41: 25
        line 42: 35
        line 43: 42
        line 44: 49
        line 45: 56
        line 46: 63
        line 47: 71
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      72     0  args   [Ljava/lang/String;
           15      57     1 byteCodeMain   Lvip/meet/base/bytecode/ByteCodeMain;
           42      30     2 resultNum   I
           56      16     3 resultStr   Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args
}
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.coloradmin.cn/o/2133611.html

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

相关文章

Alinx MPSoC驱动开发第11章异步IO实验按下按键报IO Possibile后结束进程

实验现象 使用Alinux官方提供的驱动和应用程序代码&#xff0c;petalinux工程基于自身需要进行了一定的修改&#xff08;主要是SD卡根文件系统&#xff09;。在把petalinux工程编译后打包的boot.scr、BOOT.BIN、image.ub放入FAT分区&#xff0c;把驱动程序与应用程序放在NFS共享…

万界星空科技电池MES具体功能及解决方案

电池的生产工艺具有高度的复杂性和精细度。从原材料的准备、电池的组装到最终的测试与包装&#xff0c;每一道工序都需要严格控制&#xff0c;以确保产品的质量和性能。 万界星空科技在电池MES&#xff08;制造执行系统&#xff09;领域提供了全面的解决方案&#xff0c;这些解…

JavaWeb项目打包、部署至Tomcat并启动的全程指南(图文详解)

前言 我们想要部署一个javaWeb项目到tomcat上&#xff0c;需要了解一些概念 什么是tomcat&#xff1f; Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;下的一个开源项目&#xff0c;主要用于实现 Java Servlet、JavaServer Pages&#xff08;…

在 PyCharm 中配置 Anaconda 环境

1. 安装 Anaconda 如果尚未安装 Anaconda&#xff0c;你可以从 Anaconda 官方网站 下载或者从清华镜像网站下载并安装适合你操作系统的版本。 2. 创建 Anaconda 虚拟环境 打开 Anaconda Prompt&#xff08;Windows&#xff09;或终端&#xff08;macOS/Linux&#xff09;。 …

EmguCV学习笔记 VB.Net 11.6 图像分割

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

如何升级用 Helm 安装的极狐GitLab Runner?

本分分享如何对 Helm 安装的 Runner 进行升级。整个过程分为三步&#xff1a;1、确定 Runner 最新版本或者想要升级的版本是否存在&#xff1b;2、用 Helm upgrade 命令进行升级&#xff1b;3、升级确认。 极狐GitLab 为 GitLab 的中国发行版&#xff0c;中文版本对中国用户更…

【西电电装实习】6. 手装无人机的蓝牙断连debug

文章目录 前言零、闪灯状态零零、翻滚角&#xff0c;俯仰角&#xff0c;偏航角一、问题描述二、现象解释三、解决方案参考文献 前言 在 西电无人机电装实习 时遇到的问题使用蓝牙芯片 CH582F。沁恒的蓝牙芯片CH582F是一款集成了BLE&#xff08;Bluetooth Low Energy&#xff0…

华为初级认证HCIA怎么样?

想在网络技术领域实现职业突破吗&#xff1f;华为HCIA初级认证是专为网络领域的新手与初学者设计的一项入门级认证。它旨在评估并确认个人对网络基本原理和技术知识的扎实掌握&#xff0c;是步入华为认证体系大门的基石。 一、华为HCIA 初级认证概述 华为初级认证网络工程师&am…

分类预测|基于黑翅鸢优化核极限学习机的数据分类预测Matlab程序BKA-KELM 多特征输入多类别输出 含基础KELM

分类预测|基于黑翅鸢优化核极限学习机的数据分类预测Matlab程序BKA-KELM 多特征输入多类别输出 含基础KELM 文章目录 一、基本原理BKA-HKELM 分类预测原理和流程总结 二、实验结果三、核心代码四、代码获取五、总结 一、基本原理 BKA-HKELM 分类预测原理和流程 1. 黑翅鸢优化…

最好用的翻译器:什么是DeepL?如何订阅支付DeepL,订阅DeepL Pro以及申请DeepL API?

DeepL目前最好用的翻译软件&#xff0c;如果是学习翻译的同学或者海外客户翻译&#xff0c;一定不能错过&#xff0c;用它来处理文件&#xff0c;论文等翻译是最好不过了的&#xff01;&#xff01;&#xff01; AI翻译技术的飞速发展正在颠覆我们的沟通方式&#xff0c;打破语…

6年前倒闭的机器人独角兽,再次杀入AGV市场

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 在科技创新的浪潮中&#xff0c;一个曾经辉煌又迅速陨落的企业正悄然重生&#xff0c;引发业界广泛关注。 曾经的协作机器人鼻祖Rethink Robotic…

机器学习周报(9.9-9.15)-Pytorch学习(三)

文章目录 摘要Abstract1 损失函数与反向传播1.1 L1Loss损失函数1.2 MSELoss损失函数1.3 交叉熵损失函数&#xff08;CrossEntropyLoss&#xff09;1.4 反向传播 2 优化器3 现有网络模型的使用及修改4 网络模型的保存与读取4.1 保存模型4.2 读取 总结 摘要 本次学习对Pytorch中…

8.3Sobel算子边缘检测

实验原理 Sobel算子是一种广泛使用的一阶导数边缘检测算子&#xff0c;它通过计算图像在水平和垂直方向上的梯度来检测边缘。Sobel算子使用一对3x3的掩模来实现这一功能。相比于其他边缘检测算子&#xff0c;Sobel算子在检测边缘的同时还能提供一定的抗噪能力。 在OpenCV中&a…

【射频通信电子线路基础第四讲】LC匹配网络、史密斯圆图、噪声与噪声系数

一、LC匹配网络 1、L-I型&#xff08;负载与电抗并联&#xff09; 2、L-II型&#xff08;负载与电抗串联&#xff09; 3、T型网络和π型网络例子 二、Smith圆图 这里先附上知乎大神的讲解链接&#xff0c;推荐直接去看非常适合入门理解&#xff0c;看完之后茅塞顿开 https://…

MySQL 安全机制全面解析

‍ 在如今的数字化时代&#xff0c;数据库安全 变得越来越重要。为了防止对数据库进行非法操作&#xff0c;MySQL 定义了一套完整的安全机制&#xff0c;包括用户管理、权限管理 和 角色管理。本文将为你深入浅出地介绍这三大安全机制&#xff0c;帮助你轻松掌握MySQL的安全管…

MPP数据库之SelectDB

SelectDB 是一个高性能、云原生的 MPP&#xff08;大规模并行处理&#xff09;数据库&#xff0c;旨在为分析型数据处理场景提供快速、弹性和高效的解决方案。它专为处理大规模结构化和半结构化数据设计&#xff0c;常用于企业级业务分析、实时分析和决策支持。 SelectDB 是在…

Vue2时间轴组件(TimeLine/分页、自动顺序播放、暂停、换肤功能、时间选择,鼠标快速滑动)

目录 1介绍背景 2实现原理 3组件介绍 4代码 5其他说明 1介绍背景 项目背景是 一天的时间轴 10分钟为一间隔 一天被划分成144个节点 一页面12个节点 代码介绍的很详细 可参考或者借鉴 2实现原理 对Element-plus滑块组件的二次封装 基于Vue2&#xff08;2.6.14&#x…

数字孪生引领智慧医院革新:未来医疗的智能化之路

数字孪生&#xff08;Digital Twin&#xff09; 是指将物理实体或系统的数字化模型与其实时运行数据相结合&#xff0c;以反映实体的状态、行为和性能&#xff0c;并通过数据分析和仿真来优化决策和管理。在智慧医院建设中&#xff0c;数字孪生技术扮演着关键角色。 1. 数字孪生…

基于SpringBoot+Vue的瑜伽体验课预约管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

国内按月/季/年使用GPT4.0及OpenAI最新的模型

其实gpt官方版本不仅对于网络要求很高&#xff0c;且订阅用户对高级模型的使用也是有次数限制的&#xff0c; 国内想要稳定且最快同步官网的最新模型&#xff0c;我推荐一个地址,可以方便的不限次数的使用GPT4.0等模型&#xff0c; 今天早上刚出的OpenAI全新的草莓模型&#xf…