前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Class文件进阶详解

Class文件进阶详解

原创
作者头像
kwan的解忧杂货铺
发布2024-08-17 14:04:00
1010
发布2024-08-17 14:04:00
举报
文章被收录于专栏:基础

1.基本信息

  1. 警告信息显示源 class 文件名称
  2. Classfile 显示了 class 文件的详细地址信息
  3. 最后一次的更新时间
  4. class 文件的字节大小
  5. MD5 值 checksum
  6. class 文件的编译来源文件
代码语言:apl
复制
警告: 二进制文件Student包含com.kwan.springbootkwan.entity.Student
Classfile /Users/qinyingjie/Documents/idea-workspace/vue-springboot-kwan/target/classes/com/kwan/springbootkwan/entity/Student.class
  Last modified 2023-12-2; size 4370 bytes
  MD5 checksum 7683c822cf8c123129e8867436bb50ef
  Compiled from "Student.java"

2.头部信息

  1. class 文件名
  2. 继承信息
  3. 实现接口信息
  4. 次版本号
  5. 主版本号
  6. 访问标志 flags
代码语言:apl
复制
public class com.kwan.springbootkwan.entity.Student extends com.baomidou.mybatisplus.extension.activerecord.Model<com.kwan.springbootkwan.entity.Student> implements java.io.Serializable
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER

在 Java 类文件的访问标志(Access Flags)中,ACC_PUBLICACC_SUPER是两个常见的标志,它们用于描述类的访问修饰符和其他特性。

ACC_PUBLIC:

意义:表示该类是公共的,可以被其他类访问。 解释:具有ACC_PUBLIC标志的类对于其他类是可见的,可以在同一包中或不同包中的其他类中访问。这是 Java 中最广泛使用的类访问修饰符。

ACC_SUPER:

意义:表示该类调用超类的方法时使用invokespecial指令。 解释:ACC_SUPER标志在类文件中用于指示是否调用超类(父类)的方法时使用invokespecial指令。在 Java 虚拟机规范的早期版本中,用于实现虚拟方法调用的指令是invokespecial,它被用来调用超类中的构造方法。后来,随着 Java 语言的发展,invokespecial也用于调用私有方法、实例初始化方法和初始化方法。

注意:

在 Java 5 及以后的版本中,虚拟机对于ACC_SUPER标志的使用发生了变化,实际上这个标志的作用不再与invokespecial指令有关。它仍然会被设置,但是在实际的虚拟机实现中可能没有直接的影响。

总体而言,ACC_PUBLIC表示类是公共的,可以被其他类访问,而ACC_SUPER在过去用于指示虚拟机在方法调用时使用invokespecial指令。

3.常量池总结

常量池是类文件中存储常量的表,包括类的如下几种信息:

字段(Fieldref):

  • 类的字段对应的Fieldref(字段引用常量)也存放在常量池中。

方法名(类方法和父类方法Methodref):

  • 父类方法的 init 方法会被当做Methodref(方法引用常量)存放在常量池中。
  • 本类中方法引用,如 canEqual 方法的引用也会放在常量池中,主要是重写 equals 方法。

方法描述符(Utf8):

  • setId 方法的参数是 Integer,返回值是 void,会作为一个整体以 UTF-8 编码的方式存在常量池。

字符串(String或者Utf8):

  • new 出来的 qinyuchen 这个字符串会以字符串的形式存放在常量池。
  • ApiModelProperty 注解的描述会以字符串的形式存储在常量池中,区别是以 UTF-8 编码的。
  • toString 方法模版生成的字符串也是以 utf-8 编码的形式存在常量池中。
  • toString 底层是使用 StringBuilder,然后用到了 append 方法,append 方法名也会存在常量池。
  • 方法表中的属性表中的 ConstantValue 属性存储了 static final 修饰的 utf-8 编码的常量,可以直接被类访问,如qinyingjie1
  • 只被 static 修饰的字符串以 String 形式存储在常量池中,如qinyingjie2
  • 只被 final 修饰的字符串以 String 形式存储在常量池中,如qinyingjie_nameNoStatic
  • 没有被 static final 修饰的字符串以 String 形式存储在常量池中,如qinyingjie_noneName

类引用(Class):

  • Model 类是继承的类,类引用常量也会放在常量池中。
  • 使用到了 Integer,Integer 的类引用也会存在常量池。

4.常量池中的信息

  • 常量池中的第一位,如果有静态方法,并且静态方法中有字符串,则第一位会给这个字符串。
  • 如果没有静态方法,则第一位给父类的构造方法。

以下是一些常量池中的信息(这一部分的class常量池文件是没加静态方法getStr的文件):

  1. #1 = Methodref #35.#126:
    • 这是一个方法引用(Methodref)常量,表示对com/baomidou/mybatisplus/extension/activerecord/Model类中名为<init>且没有参数的构造方法的引用。
  2. #2 = Fieldref #7.#127:
  • 这是一个字段引用(Fieldref)常量,表示对com/kwan/springbootkwan/entity/Student类中名为id的字段的引用。
  1. #8 = Methodref #7.#133:
  • 这是一个方法引用(Methodref)常量,表示对com/kwan/springbootkwan/entity/Student类中名为canEqual的方法的引用。
  1. #32 = String #158:
  • 这是一个字符串常量,表示字符串"qinyuchen"。
  1. #35 = Class #161:
  • 这是一个类引用(Class)常量,表示对com/baomidou/mybatisplus/extension/activerecord/Model类的引用。
  1. #54 = Utf8 Lio/swagger/annotations/ApiModelProperty;:
  • 这是一个 UTF-8 编码的字符串,表示io.swagger.annotations.ApiModelProperty注解的类描述。
  1. #82 = Utf8 (Ljava/lang/Integer;)V:
  • 这是一个 UTF-8 编码的方法描述符,表示方法setId的参数为Integer,返回值为void
  1. #143 = Utf8 Student(id=:
  • 这是一个 UTF-8 编码的字符串,表示字符串"Student(id="。
  1. #165 = Utf8 append:
  • 这是一个 UTF-8 编码的字符串,表示方法append
  1. #168 = Class #168:
  • 这是一个类引用(Class)常量,表示对java/lang/Integer类的引用。

这只是常量池的一小部分,每个常量都有特定的类型和含义。常量池中的信息用于描述类的结构、字段、方法等。上述解析结果是对常量池中一些常见常量的简要说明。如果需要更详细的分析,可能需要查看整个常量池的内容。

代码语言:java
复制
Constant pool:
    #1 = Methodref          #35.#126      // com/baomidou/mybatisplus/extension/activerecord/Model."<init>":()V
    #2 = Fieldref           #7.#127       // com/kwan/springbootkwan/entity/Student.id:Ljava/lang/Integer;
    #3 = Fieldref           #7.#128       // com/kwan/springbootkwan/entity/Student.question:Ljava/lang/String;
    #4 = Fieldref           #7.#129       // com/kwan/springbootkwan/entity/Student.response:Ljava/lang/String;
    #5 = Fieldref           #7.#130       // com/kwan/springbootkwan/entity/Student.createTime:Ljava/util/Date;
    #6 = Fieldref           #7.#131       // com/kwan/springbootkwan/entity/Student.isDelete:Ljava/lang/Integer;
    #7 = Class              #132          // com/kwan/springbootkwan/entity/Student
    #8 = Methodref          #7.#133       // com/kwan/springbootkwan/entity/Student.canEqual:(Ljava/lang/Object;)Z
    #9 = Methodref          #7.#134       // com/kwan/springbootkwan/entity/Student.getId:()Ljava/lang/Integer;
   #10 = Methodref          #135.#136     // java/lang/Object.equals:(Ljava/lang/Object;)Z
   #11 = Methodref          #7.#137       // com/kwan/springbootkwan/entity/Student.getIsDelete:()Ljava/lang/Integer;
   #12 = Methodref          #7.#138       // com/kwan/springbootkwan/entity/Student.getQuestion:()Ljava/lang/String;
   #13 = Methodref          #7.#139       // com/kwan/springbootkwan/entity/Student.getResponse:()Ljava/lang/String;
   #14 = Methodref          #7.#140       // com/kwan/springbootkwan/entity/Student.getCreateTime:()Ljava/util/Date;
   #15 = Methodref          #135.#141     // java/lang/Object.hashCode:()I
   #16 = Class              #142          // java/lang/StringBuilder
   #17 = Methodref          #16.#126      // java/lang/StringBuilder."<init>":()V
   #18 = String             #143          // Student(id=
   #19 = Methodref          #16.#144      // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #20 = Methodref          #16.#145      // java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
   #21 = String             #146          // , question=
   #22 = String             #147          // , response=
   #23 = String             #148          // , createTime=
   #24 = String             #149          // , isDelete=
   #25 = String             #150          // )
   #26 = Methodref          #16.#151      // java/lang/StringBuilder.toString:()Ljava/lang/String;
   #27 = String             #152          // qinyingjie2
   #28 = Fieldref           #7.#153       // com/kwan/springbootkwan/entity/Student.notFinal:Ljava/lang/String;
   #29 = Methodref          #154.#155     // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #30 = Fieldref           #7.#156       // com/kwan/springbootkwan/entity/Student.num:Ljava/lang/Integer;
   #31 = Class              #157          // java/lang/String
   #32 = String             #158          // qinyuchen
   #33 = Methodref          #31.#159      // java/lang/String."<init>":(Ljava/lang/String;)V
   #34 = Fieldref           #7.#160       // com/kwan/springbootkwan/entity/Student.newStr:Ljava/lang/String;
   #35 = Class              #161          // com/baomidou/mybatisplus/extension/activerecord/Model
   #36 = Class              #162          // java/io/Serializable
   #37 = Utf8               serialVersionUID
   #38 = Utf8               J
   #39 = Utf8               ConstantValue
   #40 = Long               1l
   #42 = Utf8               name
   #43 = Utf8               Ljava/lang/String;
   #44 = String             #163          // qinyingjie1
   #45 = Utf8               notFinal
   #46 = Utf8               num
   #47 = Utf8               Ljava/lang/Integer;
   #48 = Utf8               intnum
   #49 = Utf8               I
   #50 = Integer            30
   #51 = Utf8               newStr
   #52 = Utf8               id
   #53 = Utf8               RuntimeVisibleAnnotations
   #54 = Utf8               Lio/swagger/annotations/ApiModelProperty;
   #55 = Utf8               value
   #56 = Utf8               主键id
   #57 = Utf8               question
   #58 = Utf8               问题
   #59 = Utf8               response
   #60 = Utf8               回答
   #61 = Utf8               createTime
   #62 = Utf8               Ljava/util/Date;
   #63 = Utf8               创建时间
   #64 = Utf8               isDelete
   #65 = Utf8               删除标识
   #66 = Utf8               <init>
   #67 = Utf8               ()V
   #68 = Utf8               Code
   #69 = Utf8               LineNumberTable
   #70 = Utf8               LocalVariableTable
   #71 = Utf8               this
   #72 = Utf8               Lcom/kwan/springbootkwan/entity/Student;
   #73 = Utf8               getId
   #74 = Utf8               ()Ljava/lang/Integer;
   #75 = Utf8               getQuestion
   #76 = Utf8               ()Ljava/lang/String;
   #77 = Utf8               getResponse
   #78 = Utf8               getCreateTime
   #79 = Utf8               ()Ljava/util/Date;
   #80 = Utf8               getIsDelete
   #81 = Utf8               setId
   #82 = Utf8               (Ljava/lang/Integer;)V
   #83 = Utf8               MethodParameters
   #84 = Utf8               setQuestion
   #85 = Utf8               (Ljava/lang/String;)V
   #86 = Utf8               setResponse
   #87 = Utf8               setCreateTime
   #88 = Utf8               (Ljava/util/Date;)V
   #89 = Utf8               setIsDelete
   #90 = Utf8               equals
   #91 = Utf8               (Ljava/lang/Object;)Z
   #92 = Utf8               o
   #93 = Utf8               Ljava/lang/Object;
   #94 = Utf8               other
   #95 = Utf8               this$id
   #96 = Utf8               other$id
   #97 = Utf8               this$isDelete
   #98 = Utf8               other$isDelete
   #99 = Utf8               this$question
  #100 = Utf8               other$question
  #101 = Utf8               this$response
  #102 = Utf8               other$response
  #103 = Utf8               this$createTime
  #104 = Utf8               other$createTime
  #105 = Utf8               StackMapTable
  #106 = Class              #132          // com/kwan/springbootkwan/entity/Student
  #107 = Class              #164          // java/lang/Object
  #108 = Utf8               canEqual
  #109 = Utf8               hashCode
  #110 = Utf8               ()I
  #111 = Utf8               PRIME
  #112 = Utf8               result
  #113 = Utf8               $id
  #114 = Utf8               $isDelete
  #115 = Utf8               $question
  #116 = Utf8               $response
  #117 = Utf8               $createTime
  #118 = Utf8               toString
  #119 = Utf8               <clinit>
  #120 = Utf8               Signature
  #121 = Utf8               Lcom/baomidou/mybatisplus/extension/activerecord/Model<Lcom/kwan/springbootkwan/entity/Student;>;Ljava/io/Serializable;
  #122 = Utf8               SourceFile
  #123 = Utf8               Student.java
  #124 = Utf8               Lio/swagger/annotations/ApiModel;
  #125 = Utf8               chatgpt问答实体类
  #126 = NameAndType        #66:#67       // "<init>":()V
  #127 = NameAndType        #52:#47       // id:Ljava/lang/Integer;
  #128 = NameAndType        #57:#43       // question:Ljava/lang/String;
  #129 = NameAndType        #59:#43       // response:Ljava/lang/String;
  #130 = NameAndType        #61:#62       // createTime:Ljava/util/Date;
  #131 = NameAndType        #64:#47       // isDelete:Ljava/lang/Integer;
  #132 = Utf8               com/kwan/springbootkwan/entity/Student
  #133 = NameAndType        #108:#91      // canEqual:(Ljava/lang/Object;)Z
  #134 = NameAndType        #73:#74       // getId:()Ljava/lang/Integer;
  #135 = Class              #164          // java/lang/Object
  #136 = NameAndType        #90:#91       // equals:(Ljava/lang/Object;)Z
  #137 = NameAndType        #80:#74       // getIsDelete:()Ljava/lang/Integer;
  #138 = NameAndType        #75:#76       // getQuestion:()Ljava/lang/String;
  #139 = NameAndType        #77:#76       // getResponse:()Ljava/lang/String;
  #140 = NameAndType        #78:#79       // getCreateTime:()Ljava/util/Date;
  #141 = NameAndType        #109:#110     // hashCode:()I
  #142 = Utf8               java/lang/StringBuilder
  #143 = Utf8               Student(id=
  #144 = NameAndType        #165:#166     // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #145 = NameAndType        #165:#167     // append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
  #146 = Utf8               , question=
  #147 = Utf8               , response=
  #148 = Utf8               , createTime=
  #149 = Utf8               , isDelete=
  #150 = Utf8               )
  #151 = NameAndType        #118:#76      // toString:()Ljava/lang/String;
  #152 = Utf8               qinyingjie2
  #153 = NameAndType        #45:#43       // notFinal:Ljava/lang/String;
  #154 = Class              #168          // java/lang/Integer
  #155 = NameAndType        #169:#170     // valueOf:(I)Ljava/lang/Integer;
  #156 = NameAndType        #46:#47       // num:Ljava/lang/Integer;
  #157 = Utf8               java/lang/String
  #158 = Utf8               qinyuchen
  #159 = NameAndType        #66:#85       // "<init>":(Ljava/lang/String;)V
  #160 = NameAndType        #51:#43       // newStr:Ljava/lang/String;
  #161 = Utf8               com/baomidou/mybatisplus/extension/activerecord/Model
  #162 = Utf8               java/io/Serializable
  #163 = Utf8               qinyingjie1
  #164 = Utf8               java/lang/Object
  #165 = Utf8               append
  #166 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #167 = Utf8               (Ljava/lang/Object;)Ljava/lang/StringBuilder;
  #168 = Utf8               java/lang/Integer
  #169 = Utf8               valueOf
  #170 = Utf8               (I)Ljava/lang/Integer;

5.canEqual

canEqual 方法通常用于实现 Java 中的 equals 方法。在实现类的 equals 方法时,通常需要遵循一些约定,其中之一是覆盖 equals 方法时也要覆盖 hashCode 方法。在实现 equals 方法时,需要比较两个对象的类型,以防止比较不同类型的对象。

canEqual 方法用于检查传入的对象是否是相同类的实例,这是为了确保在比较两个对象时不会因为类型不同而导致错误。通常,canEqual 方法的实现会使用 instanceof 运算符来进行类型检查。

代码语言:java
复制
protected boolean canEqual(final Object other) {
        return other instanceof Student;
}

6.构造方法说明

  • class 文件中方法会被{}括起来
  • Student()标识是 Student 类的构造函数
代码语言:java
复制
{
  public com.kwan.springbootkwan.entity.Student();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method com/baomidou/mybatisplus/extension/activerecord/Model."<init>":()V
         4: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/kwan/springbootkwan/entity/Student;
}

这是一个默认构造方法的字节码表示,对应于 com.kwan.springbootkwan.entity.Student 类的构造方法。下面是对该字节码的详细解释:

  • public com.kwan.springbootkwan.entity.Student();
  • 这是构造方法的声明,表示一个公共的无参数构造方法,属于 com.kwan.springbootkwan.entity.Student 类。
  • descriptor: ()V
  • 描述符表示方法的签名,这里 () 表示无参数,V 表示返回类型为 void
  • flags: ACC_PUBLIC
  • 表示该方法是公共的。
  • Code:
  • 下面是方法的字节码指令。
  • stack=1, locals=1, args_size=1
    • 这是关于操作数栈局部变量方法参数大小的信息。
    • 对于无参数方法,这三个值通常都是 1。
    • stack表示方法的操作数栈的最大深度,即在方法执行期间,最多同时存在多少个数值在操作数栈上。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
    • locals表示局部变量表的大小,即方法在执行期间可以使用的局部变量槽位数量。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
    • args_size表示方法的参数数量。对于无参数方法,参数数量为 1,即当前对象引用(this)。
  • 0: aload_0
    • 将当前对象引用(this)加载到操作数栈上。
    • 0 代表字节码中的第 0 条指令。偏移量是 0。
  • 1: invokespecial #1
    • 调用父类构造方法。invokespecial 是用于调用特殊方法(比如构造方法、私有方法)的指令。#1 是对常量池中索引为 1 的方法引用的引用。
    • 1 代表字节码中的第 1 条指令。偏移量是 1。
  • 4: return
    • 返回,结束方法执行。
    • 4 代表字节码中的第 1 条指令。偏移量是 4。
  • LineNumberTable:
  • 表示源代码行号信息。
  • line 12: 0
    • 在源代码的第 12 行,对应于字节码的第 0 指令。
  • LocalVariableTable:
  • 表示局部变量表信息。
  • Start Length Slot Name Signature
  • 描述局部变量表的开始位置、长度、槽位、变量名和变量签名。
  • 0 5 0 this Lcom/kwan/springbootkwan/entity/Student;
    • 表示在方法执行期间,槽位为 0 的局部变量是当前对象引用,变量名为 this,类型为 Lcom/kwan/springbootkwan/entity/Student;

总体而言,这段字节码表示 com.kwan.springbootkwan.entity.Student 类的公共无参数构造方法,其中通过 aload_0 指令加载当前对象引用到操作数栈上,然后通过 invokespecial 指令调用父类构造方法,最后通过 return 指令返回。

7.get 方法说明

getId 和构造函数方法过程类似,差异不大,可以类比分析,这里具体分析省略。

代码语言:java
复制
public java.lang.Integer getId();
    descriptor: ()Ljava/lang/Integer;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field id:Ljava/lang/Integer;
         4: areturn
      LineNumberTable:
        line 28: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/kwan/springbootkwan/entity/Student;

8.set 方法说明

代码语言:java
复制
public void setId(java.lang.Integer);
    descriptor: (Ljava/lang/Integer;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field id:Ljava/lang/Integer;
         5: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/kwan/springbootkwan/entity/Student;
            0       6     1    id   Ljava/lang/Integer;
    MethodParameters:
      Name                           Flags
      id                             final

这段字节码对应于一个 Java 方法,该方法名为 setId,参数为一个 java.lang.Integer 类型的对象。下面是对这段字节码的详细解析:

  • public void setId(java.lang.Integer);
  • 这是方法的声明,表示一个公共的无返回值方法,名为 setId,接受一个 java.lang.Integer 类型的参数。
  • descriptor: (Ljava/lang/Integer;)V
  • 方法的描述符,指定了方法的签名。这里 (Ljava/lang/Integer;)V 表示方法接受一个 java.lang.Integer 类型的参数,返回类型为 void
  • flags: ACC_PUBLIC
  • 表示该方法是公共的。
  • Code:
  • 下面是方法的字节码指令。
  • stack=2, locals=2, args_size=2
  • stack=2 表示方法的操作数栈的最大深度是 2。
  • locals=2 表示局部变量表的大小是 2。
  • args_size=2 表示方法的参数数量是 2。
  • 0: aload_0
  • 将当前对象的引用(this)加载到操作数栈上。
  • 1: aload_1
  • 将方法参数 id 的值加载到操作数栈上。
  • 2: putfield #2
  • 将操作数栈顶的值(id)赋值给对象的字段。#2 表示常量池中索引为 2 的字段引用。
  • 5: return
  • 返回,结束方法执行。
  • LineNumberTable:
  • 表示源代码行号信息。
  • line 12: 0
  • 在源代码的第 12 行,对应于字节码的第 0 指令。
  • LocalVariableTable:
  • 表示局部变量表信息。
  • Start Length Slot Name Signature
  • 描述局部变量表的开始位置、长度、槽位、变量名和变量签名。
  • 0 6 0 this Lcom/kwan/springbootkwan/entity/Student;
  • 表示在方法执行期间,槽位为 0 的局部变量是当前对象引用,变量名为 this,类型为 Lcom/kwan/springbootkwan/entity/Student;
  • 0 6 1 id Ljava/lang/Integer;
  • 表示在方法执行期间,槽位为 1 的局部变量是参数 id,类型为 Ljava/lang/Integer;
  • MethodParameters:
  • 表示方法参数的信息。
  • Name Flags
  • 参数的名称和标志。
  • id final
    • 参数的名称为 id,并且标记为 final

9.常量方法

代码语言:apl
复制
static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=3, locals=0, args_size=0
         0: ldc           #27                 // String qinyingjie2
         2: putstatic     #28                 // Field notFinal:Ljava/lang/String;
         5: bipush        20
         7: invokestatic  #29                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        10: putstatic     #30                 // Field num:Ljava/lang/Integer;
        13: new           #31                 // class java/lang/String
        16: dup
        17: ldc           #32                 // String qinyuchen
        19: invokespecial #33                 // Method java/lang/String."<init>":(Ljava/lang/String;)V
        22: putstatic     #34                 // Field newStr:Ljava/lang/String;
        25: return
      LineNumberTable:
        line 19: 0
        line 21: 5
        line 25: 13

10.操作数栈和局部变量表区别?

stack=1, locals=1, args_size=1

  • 这是关于操作数栈局部变量方法参数大小的信息。
  • 对于无参数方法,这三个值通常都是 1。
  • stack表示方法的操作数栈的最大深度,即在方法执行期间,最多同时存在多少个数值在操作数栈上。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
  • locals表示局部变量表的大小,即方法在执行期间可以使用的局部变量槽位数量。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
  • args_size表示方法的参数数量。对于无参数方法,参数数量为 1,即当前对象引用(this)。

操作数栈(Operand Stack)和局部变量表(Local Variable Table)是 Java 虚拟机(JVM)中两个关键的数据结构,用于支持方法的执行。它们在存储和管理数据的方式上有一些重要的区别:

操作数栈(Operand Stack):

  • 作用: 操作数栈是一个后进先出(LIFO)的栈,用于存储方法执行期间的临时数据中间结果。它是一种运算时的工作区,用于保存方法调用过程中产生的数据以及进行操作数的压栈弹栈操作。
  • 访问: JVM 的字节码指令通常包括对操作数栈的读写操作。例如,将数据推入操作数栈、弹出数据、进行算术运算等。
  • 生命周期: 操作数栈中的数据生命周期短暂,仅在方法的执行期间有效。当方法调用结束时,操作数栈的内容也被销毁。

局部变量表(Local Variable Table):

  • 作用: 局部变量表是一个数组,用于存储方法中的局部变量。局部变量包括方法参数临时变量以及在方法体内部定义其他变量。与操作数栈不同,局部变量表的数据在方法的整个生命周期内都是可访问的。
  • 访问: 局部变量表通过索引来访问,而不像操作数栈那样通过栈顶指针。变量的访问是直接的,通过索引来定位,而不需要像操作数栈那样进行栈顶的推入和弹出操作。
  • 生命周期: 局部变量表中的数据的生命周期长于操作数栈,它们在整个方法的执行过程中都可以被访问。

总的来说,操作数栈主要用于执行方法过程中的计算和操作,而局部变量表则用于存储方法中的局部变量。这两个数据结构协同工作,支持方法的正确执行。

11.方法表总结

  • 静态方法放在第一位,然后是构造方法,最后是其他方法
  • 方法声明,方法表用{}括起来,里面都是方法
  • 方法描述符和方法签名(descriptor)
  • 方法访问标志(flags)
  • 方法的字节码指令(code)
  • 方法的参数信息(MethodParameters)
代码语言:apl
复制
{
  public com.kwan.springbootkwan.entity.Student();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method com/baomidou/mybatisplus/extension/activerecord/Model."<init>":()V
         4: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/kwan/springbootkwan/entity/Student;
}

12.方法的字节码指令

方法的字节码指令(code)包含如下内容

  • 操作数栈
  • 局部变量表
  • 方法参数大小
  • 源代码行号信息
  • 局部变量表的详细信息
  • 方法参数的详细信息
代码语言:java
复制
{
  public com.kwan.springbootkwan.entity.Student();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method com/baomidou/mybatisplus/extension/activerecord/Model."<init>":()V
         4: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/kwan/springbootkwan/entity/Student;
}
  • Code:
  • 下面是方法的字节码指令。
  • stack=1, locals=1, args_size=1
    • 这是关于操作数栈局部变量方法参数大小的信息。
    • 对于无参数方法,这三个值通常都是 1。
    • stack表示方法的操作数栈的最大深度,即在方法执行期间,最多同时存在多少个数值在操作数栈上。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
    • locals表示局部变量表的大小,即方法在执行期间可以使用的局部变量槽位数量。对于无参数方法,通常只需一个槽位来存储当前对象的引用(this)。
    • args_size表示方法的参数数量。对于无参数方法,参数数量为 1,即当前对象引用(this)。
  • 0: aload_0
    • 将当前对象引用(this)加载到操作数栈上。
    • 0 代表字节码中的第 0 条指令。偏移量是 0。
  • 1: invokespecial #1
    • 调用父类构造方法。invokespecial 是用于调用特殊方法(比如构造方法、私有方法)的指令。#1 是对常量池中索引为 1 的方法引用的引用。
    • 1 代表字节码中的第 1 条指令。偏移量是 1。
  • 4: return
    • 返回,结束方法执行。
    • 4 代表字节码中的第 1 条指令。偏移量是 4。
  • LineNumberTable:
  • 表示源代码行号信息。
  • line 12: 0
  • 在源代码的第 12 行,对应于字节码的第 0 指令。
  • LocalVariableTable:
  • 表示局部变量表信息。
  • Start Length Slot Name Signature
    • 描述局部变量表的开始位置、长度、槽位、变量名和变量签名。
  • 0 5 0 this Lcom/kwan/springbootkwan/entity/Student;
    • 表示在方法执行期间,槽位为 0 的局部变量是当前对象引用,变量名为 this,类型为 Lcom/kwan/springbootkwan/entity/Student;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.基本信息
  • 2.头部信息
  • 3.常量池总结
  • 4.常量池中的信息
  • 5.canEqual
  • 6.构造方法说明
  • 7.get 方法说明
  • 8.set 方法说明
  • 9.常量方法
  • 10.操作数栈和局部变量表区别?
  • 11.方法表总结
  • 12.方法的字节码指令
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档