JAVA字节码文件分析(一)

​​​​Java不只是一种编程语言,还是一个完整的操作平台。Java之所以可以跨平台,这离不开JVM虚拟机。

JVM是一个软件,在不同的平台上,JVM有不同的版本。Java在编译之后会生成一种.class文件,这种文件成为字节码文件。JVM虚拟机就是将Java编译后的.class文件翻译成特定平台下的机器码,然后运行。也就是说,在不同平台上装上平台对应的JVM虚拟机后,就可以将Java字节码文件转换,然后运行我们的Java程序。

值得注意的是,Java编译后的结果是生成字节码,而不是机器码。字节码是不可以直接运行的,必须通过JVM再次翻译成机器码才可以运行。即使是将Java程序打包成可执行文件,也仍然需要JVM的支持才可以运行。

跨平台的是Java程序,而不是JVM。JVM是用C/C++开发的,不能平台,不同的平台下JVM的版本是不同的。

字节码文件,有什么用?

JVM虚拟机的特点:一处编译,多处运行。

多处运行,靠的是.class 字节码文件。

JVM本身,并不是跨平台的。Java之所以跨平台,是因为JVM本身不夸平台。

二进制的文件,显然不是给人看的。是给机器看的。

从根源了解了之后,返回到语言层次 好多都会豁然开朗。

Java语言规范补充:

JVM虚拟机规范(相对底层的)Java,Groovy,kotlin,Scala。 编译后都是Class文件,所以就都能在JVM虚拟机上运行。

字节码结构

一、整体结构

在这里插入图片描述
在这里插入图片描述
1、魔数
2、版本号
3、常量池数-1
4、常量池数组(常量池中的每个常量的具体信息)
5、当前类的访问控制权限(private,public , pro , 等几种 当前类的标识符)
6、当前类的名字
7、父类的名字
8、当前类的接口信息
9、当前类的成员变量的信息
10、当前类的方法的信息
11、当前类附加的属性

Class字节码中有两种数据类型
1、字节数据直接量:这是基本的数据类型。共细分为u1、u2、u4、u8四种,分表代表连续的1个字节、2个字节、4个字节、8个字节组成的整体数据。
2、表(数组):表是由多个基本数据或其他表,按照既定顺序组成的大的数据集合。表是由结构的,它的结构体现在:组成表的成分所在的位置和顺序都是已经严格定义好的。

二、class文件反编译结果

package com.shengsiyuan.jvm.bytecode;
public class MyTest1 {
    private int a = 1;
    public int getA() { return a; }
    public void setA(int a) { this.a = a; }
}

反编译命令:

javap -verbose com.shengsiyuan.jvm.bytecode.MyTest1

结果:

C:\eclipse-workspace-photon\jvm\target\classes\com\shengsiyuan\jvm\bytecode>javap -v MyTest1.class
Classfile /C:/eclipse-workspace-photon/jvm/target/classes/com/shengsiyuan/jvm/bytecode/MyTest1.class
  Last modified 2020-4-7; size 499 bytes
  MD5 checksum 5a1d73bf3e8fff630dea123993620ea6
  Compiled from "MyTest1.java"
public class com.shengsiyuan.jvm.bytecode.MyTest1
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#21         // com/shengsiyuan/jvm/bytecode/MyTest1.a:I
   #3 = Class              #22            // com/shengsiyuan/jvm/bytecode/MyTest1
   #4 = Class              #23            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/shengsiyuan/jvm/bytecode/MyTest1;
  #14 = Utf8               getA
  #15 = Utf8               ()I
  #16 = Utf8               setA
  #17 = Utf8               (I)V
  #18 = Utf8               SourceFile
  #19 = Utf8               MyTest1.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = NameAndType        #5:#6          // a:I
  #22 = Utf8               com/shengsiyuan/jvm/bytecode/MyTest1
  #23 = Utf8               java/lang/Object
{
  public com.shengsiyuan.jvm.bytecode.MyTest1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 2: 0
        line 3: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/shengsiyuan/jvm/bytecode/MyTest1;

  public int getA();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field a:I
         4: ireturn
      LineNumberTable:
        line 4: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/shengsiyuan/jvm/bytecode/MyTest1;

  public void setA(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #2                  // Field a:I
         5: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/shengsiyuan/jvm/bytecode/MyTest1;
            0       6     1     a   I
}
SourceFile: "MyTest1.java"

三、查看class文件字节码

在这里插入图片描述

五、魔数

魔数:所有的.class字节码文件的前4个字节都是魔数,魔术值为固定值:0xCAFEBABE
在这里插入图片描述魔数

六、版本号

版本号:魔术之后的4个字节为jdk版本信息,前两个表示次版本号,后两个表示主版本号,这里的00 00 00 34,换成十进制,表示此版本为0(00 00),主版本号为52(00 34),该文件的版本号为 1.8.0
在这里插入图片描述
在这里插入图片描述

七、常量池

常量池中主要存储两类常量:字面量与符号引用
1、字面量:如文本字符串,java中声明为final的常量值等。
2、符号引:用如类和接口的全局限定名,字段的名称和描述符、方法的名称和描述符等。常量池:里面的值不一定都是常量。变量也是放在常量池的。

常量池的总体结构:java类所对应的常量池主要由常量池数量与常量池数组这两部分共同构成。
1、常量池数量:紧跟在主版本号后面,占据2个字节,
2、常量池数组:紧跟在常量池数量之后,常量池数组与一般的数组不同,常量池数组中不同的元素的类型、结构都是不同的,长度当然也就不同;但是 每一种元素的第一个数据都是u1类型,该字节是标志位,占据1个字节。jvm在解析常量池时,会根据这个u1类型来获取元素的具体类型。

描述信息:
1、在jvm规范中,每个变量/字段都有描述信息,描述信息主要的作用描述字段的数据类型、方法的参数列表(包括数量、类型与顺序)与返回值。根据描述符规则,基本数据类型和代表无返回值的void类型都用一个大写字符来表示,对象类型则使用字符L加对象的全限定名称来表示。为了压缩字节码文件的体积,对于基本数据类型,jvm都只使用一个大写 字母来表述如:B -byte C - char. D -double. F - float. I - int J - long、S - short 、Z - boolean、V - void、L - 对象类型,如 Ljava/lang/String;对于数组类型来说,int[] 记录为[I,String[][] 记录为[[Ljava/lang/String。
2、用描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之内,如方法 String getDetail(int id,String name)的描述为(I,Ljava/lang/String)Ljava/lang/String。

7.1常量池数量

常量池数量紧跟在主版本号后面,占据2个字节,常量池数组紧跟在常量池数量之后,常量池数组与一般的数组不同,常量池数组中不同的元素的类型、结构都是不同的,长度当然也就不同;但是 每一种元素的第一个数据都是u1类型,该字节是标志位,占据1个字节。jvm在解析常量池时,会根据这个u1类型来获取元素的具体类型。

下面我们解析一下字节码文件中常量池数量
反编译常量池
在这里插入图片描述

  1. 16进制 00 18 就是24 ,代表常量池数组长度24, 但是常量池数组中元素个数 = 常量池数 -1(其中0暂时不使用),目的是满足某些常量池索引值的数据在特定情况下需要表达“不引用任何一个常量池”的含义:根本愿意在于 索引为0也是一个常量,只不过它不位于常量表中,对应的就是null,所以常量池的索引从1开始。

7.1常量池数组

常量池数组到哪里结束,是由常量池数组里的内容长度来决定的,需要一个一个常量解析才知道具体的长度多少
在这里插入图片描述

1.第一个常量

0A 是第一个常量的标志位,占一个字节16进制是10 ,对应去找到常量池数据类型对应的值为10 的是CONSTANT_Methodref_info ,数据类型里面包含两部分,并且都是U2 类型的,表示分别占据两个字节。
在这里插入图片描述
在这里插入图片描述

  • 00 04 00 14 分别对应16进制的4和20 索引位置(指向声明方法的类的描述符);可以对应反编译结果的图进行查看到,由于会默认生成一个无参的构造方法;所以是 java/lang/object< init>:()V ,< init>:表示构造方法,()V:描述符,无参数并且无返回值
    在这里插入图片描述

2. 第二个常量

09十进制tag值为9 , 向后找四个字节 00 03 00 15 对应找十进制3和21,表示com/dawa/jvm/bytecode/MyTest1.a:I,MyTest1类下类型为I(int)的变量a
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.第三个常量

 -  07十进制tag值为7 ,后面占据两个字节 ;00 16对应十进制22 ,表示类的全限定名称:com/dawa/jvm/bytecode/MyTest1

在这里插入图片描述
在这里插入图片描述
process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hkMjAwODY5OTY=,size_16,color_FFFFFF,t_70)

4. 第四个常量

  • 07十进制tag值为7 ,向后找两个字节 00 17对应十进制23,表示:java/lang/Object,java默认父类
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5. 第五个常量

01十进制tag值为1,向后找两个字节00 01十进制为1,所以向后找1个字节,十六进制61转换ASCII结果对应a。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 第六个常量

01十进制tag值为1,向后找两个字节00 01十进制为1,所以向后找1个字节,十六进制49转换ASCII结果对应I
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.第7个常量

01十进制tag值为1,向后找两个字节00 06十进制为6,所以向后找6个字节,十六进制3c 69 6e 69 74 3e 转换ASCII结果对应< init>
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.第8个常量

01十进制tag值为1,向后找两个字节00 03十进制为3,所以向后找3个字节,十六进制28 29 56 转换ASCII结果对应( ) V
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9. 第9个常量

01十进制tag值为1,向后找两个字节00 04十进制为4,所以向后找4个字节,十六进制43 6f 64 65 转换ASCII结果对应C o d e
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10. 第10个常量

01十进制tag值为1,向后找两个字节00 0F十进制为15,所以向后找15个字节,十六进制4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 转换ASCII结果对应LineNumberTable
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.*第11个常量

01十进制tag值为1,向后找两个字节00 0F十进制为15,所以向后找15个字节,十六进制4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 转换ASCII结果对应LocalVariableTable (局部变量表)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

12. 第12个常量

01十进制tag值为1,向后找两个字节00 04十进制为4,所以向后找4个字节,十六进制74 68 69 73 转换ASCII结果对应this
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

13. 第13个常量

01十进制tag值为1,向后找两个字节00 26十进制为38,所以向后找38个字节,十六进制4c 63 6f 6d 2f 73 68 65 6e 67 73 69 79 75 61 6e 2f 6a 76 6d 2f 62 79 74 65 63 6f 64 65 2f 4d 79 54 65 73 74 31 3b 转换ASCII结果对应L c o m / s h e n g s i y u a n / j v m / b y t e c o d e / M y T e s t 1 ;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

14. 第14个常量

01十进制tag值为1,向后找两个字节00 04十进制为4,所以向后找4个字节,十六进制67 65 74 41 转换ASCII结果对应g e t A 在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

15.第15个常量

01十进制tag值为1,向后找两个字节00 03十进制为3,所以向后找3个字节,十六进制28 29 49 转换ASCII结果对应( ) I
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

16. 第16个常量

01十进制tag值为1,向后找两个字节00 04十进制为4,所以向后找4个字节,十六进制73 65 74 41 转换ASCII结果对应s e t A
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

17.第17个常量

01十进制tag值为1,向后找两个字节00 04十进制为4,所以向后找4个字节,十六进制28 49 29 56 转换ASCII结果对应( I ) V
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

18.第18个常量:

01十进制tag值为1,向后找两个字节00 0a十进制为10,所以向后找10个字节,十六进制53 6f 75 72 63 65 46 69 6c 65 转换ASCII结果对应S o u r c e F i l e
在这里插入图片描述
在这里插入图片描述

19. 第19个常量

01十进制tag值为1,向后找两个字节00 0c十进制为12,所以向后找12个字节,十六进制4d 79 54 65 73 74 31 2e 6a 61 76 61 转换ASCII结果对应MyTest1.java,17和18两个常量描述了,由源文件MyTest1.java编译而来
在这里插入图片描述
在这里插入图片描述

20. 第20个常量

0c十进制tag值为12,向后找四个字节00 07 00 08十进制分别为7和8,结果为: “”😦)V
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

21. 第21个常量

0c十进制tag值为12,向后找四个字节00 05 00 06十进制分别为5和6,结果为: “”😦)V
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

22. 第22个常量

01十进制tag值为1,向后找两个字节00 24十进制为36,所以向后找36个字节,十六进制63 6f 6d 2f 73 68 65 6e 67 73 69 79 75 61 6e 2f 6a 76 6d 2f 62 79 74 65 63 6f 64 65 2f 4d 79 54 65 73 74 31 转换ASCII结果对应com/shengsiyuan/jvm/bytecode/MyTest1
在这里插入图片描述
在这里插入图片描述

23. 第23个常量

01十进制tag值为1,向后找两个字节00 10十进制为16,所以向后找16个字节,十六进制6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 转换ASCII结果对应java/lang/Object
在这里插入图片描述
在这里插入图片描述
至此常量池部分分析完毕。

八、Access_Flag 访问标志

访问标志信息包括该class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的源代码,我们知道该文件是类并且是public
0x0021:是0x0020 和 0x0001的并集,表示 acc_public 与acc_super
在这里插入图片描述
0x0021:是0x0020 和 0x0001的并集,表示 acc_public 与acc_super
在这里插入图片描述

九、this_class 当前类名

u2类型,2个字节,00 03十进制值为3,去常量池表中查找:
在这里插入图片描述
在这里插入图片描述

十、surper_class 父类名称

u2类型,2个字节,00 04十进制值为4,去常量池表中查找:
在这里插入图片描述
在这里插入图片描述

十一、 interfaces 接口

1、 interfaces_ count接口数量

00 00十进制为0, 说明该类并没有实现接口,因此接口名不占位
在这里插入图片描述
在这里插入图片描述

2、 interfaces接口名称

十二、 fields当前类变量

在这里插入图片描述

1、fields_ count成员变量数量

00 01 表示 1个变量
在这里插入图片描述

2、fields_ info成员变量表

表结构如下:
在这里插入图片描述
在这里插入图片描述
字段表:用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包含方法内部声明的局部变量。

2.1、access_flags:

字段的作用域(public private protected)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile)、可否被序列化(transient)、字段数据类型
u2类型,00 20十进制值为2,表示private,私有的
在这里插入图片描述
在这里插入图片描述

2.2、name_indexs

变量名字索引,u2类型,00 05十进制为5
在这里插入图片描述
在这里插入图片描述

2.3、descript_index

描述符索引,u2类型,00 06十进制为6,I为int类型
在这里插入图片描述
在这里插入图片描述

2.4、attribute_counts

附加属性个数,u2类型,00 00十进制为0,则attribute_info为空在这里插入图片描述

2.5、attribute_info

十三、当前类的方法信息

在这里插入图片描述

1、methods_count方法数量

u2类型,两个字节 00 03 表示 ,有3个方法
在这里插入图片描述

2、methods_infot方法表(第一个方法)

方法表:与字段表信息一致
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.1、access_flags:

u2类型,00 01十进制值为1,表示public
在这里插入图片描述

2.2、name_index

方法名称索引,u2类型,00 07十进制为7,去常量池中查找方法为 < init>,为类的构造方法
在这里插入图片描述
在这里插入图片描述

2.3、descriptor_index

方法描述索引,u2类型,00 08十进制值为8,去常量池中查找,()V无参数无返回值
在这里插入图片描述
在这里插入图片描述

2.4、attitudes_count

方法属性个数,u2类型,00 01十进制值为1,表示有1个属性
在这里插入图片描述

2.5、attitudes_info

方法属性表,
在这里插入图片描述

2.5.1、attitude_name_index

方法属性名称索引,00 09十进制值为9,去常量池中查找为Code,code为方法的执行代码,每个方法都存在一个Code属性
在这里插入图片描述
在这里插入图片描述

2.5.2、attitude_length

u4类型,Code长度,00 00 00 38十进制为56

2.5.3、info[attitude_length]

占据56个字节长度作为Code的值,该部分代表代码所执行的信息
在这里插入图片描述

2.5.3.1、Code_attibute

下载字节码查看工具:jclasslib
结构如下:
在这里插入图片描述
查看第一個方法的Code:
在这里插入图片描述

2.5.3.1.1、max_stack

max_stack表示这个方法运行的任何时刻所能达到的操作数盏的最大深度,u2類型,00 02十进制为2,
在这里插入图片描述

2.5.3.1.2、max_locals

max_locals :表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量,u2类型,00 01十进制为1,表示只有一个局部变量
在这里插入图片描述

2.5.3.1.3、code_length

code_length:表示该方法所包含的字节码的字节数以及具体的指令码,具体字节码即是该方法被调用时,虚拟机所执行的字节码,u4类型,00 00 00 0a十进制为10,代表虚拟机执行字节码长度、

2.5.3.1.4、code[code_length]

在这里插入图片描述
在这里插入图片描述
十个长度的十六进制字节码是如何与图片二右侧的助记符相对应上的?

  • 1、点击aload_0会链接到oracel官方网站,可以查找,aload_0所对应的十六进制字节码,aload_0对应2a,aload_0含义是将栈中索引为0的栈针推送到栈顶
    在这里插入图片描述

  • 2、点击invokespecial,对应字节码b7,并且有参数,参数为00 01十进制为1,在常量池中值为:java/lang/Object."< init>"😦)V,表示执行Object(父类)中的init方法
    在这里插入图片描述

  • 3、aload_0原理同上,对应字节码2a

  • 4、 iconst_1对应字节码04,推送一个int整数1在这里插入图片描述

  • 5、putfield对应字节码b5,紧跟着00 002十进制为2,常量池中:com/shengsiyuan/jvm/bytecode/MyTest1.a:I,该方法将1赋值给a变量,赋值是在构造方法中完成的

  • 6、 return对应字节码b1,至此构造方法执行完毕

2.5.3.1.5、exception_table_length

这里存放的是处理异常的信息,构造方法不存储异常信息,u2类型,00 00
在这里插入图片描述

2.5.3.1.6、attributes_count

属性数量,u2类型,00 02十进制为2,代表有两个属性
在这里插入图片描述

2.5.3.1.7 、attribute_info,attribute[attribute_count]
  • 1、LineNumberTable
    在这里插入图片描述
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0a十进制10,常量池中对应LineNumberTable,行号表,字节码行号和java程序中的行号对应关系,当程序抛异常时才能指定异常行号

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 0a十进制为10

  • 1.3、line_table_table_length:表示有几对映射,u2类型,00 02十进制为2,表示有两对映射,字节码00 00映射java代码00 02行号为2,字节码00 004映射Java代码行号00 03行号为3
    在这里插入图片描述
    2、LocalVariableTable局部变量表
    在这里插入图片描述
    在这里插入图片描述
    结构与LineNumberTable类似
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0b十进制11,常量池中对应LocalVariableTable,

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 0c十进制为12

  • 1.3、line_table_table_length:表示有几个局部变量,u2类型 ,00 01表示有一个局部变量

  • 1.4、00 00 00 0a,表示start_pc开始位置为0,结束位置为00 0a值为10,紧接着00表示索引0

  • 1.5、0c对应常量池12位置:this当前对象,只有唯一局部变量this

  • 1.6、00 0d对应常量池13位置:Lcom/shengsiyuan/jvm/bytecode/MyTest1;描述当前对象

  • 1.7、 00 00用于校验检查

每个exception_table表项有start_pc,end_pc,handler_pc,catch_type组成

3、methods_infot方法表(第二个方法)

方法表:与字段表信息一致
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
第二个方法所有字节码

3.1、access_flags:

访问控制:u2类型,00 01十进制值为1,表示public

3.2、name_index:

方法名称索引,u2类型,00 0e:14,常量池:getA

3.3、descriptor_index

方法描述索引,u2类型,00 0f:15,常量池: ()I:,无参数返回类型int

3.4、attitudes_count

方法属性个数,u2类型,00 01十进制值为1,表示有1个属性

3.5、attitudes_info

方法属性表,

3.5.1、attitude_name_index

方法属性名称索引,00 09:9,常量池:Code,Code为方法的执行代码,每个方法都存在一个Code属性

3.5.2、attitude_length

u4类型,Code长度,00 00 00 2f十进制为47

3.5.3、info[attitude_length]

占据47个字节长度作为Code的值,该部分代表代码所执行的信息

3.5.3.1、Code_attibute
3.5.3.1.1、max_stack

max_stack表示这个方法运行的任何时刻所能达到的操作数盏的最大深度,u2類型,00 01十进制为1,
在这里插入图片描述

3.5.3.1.2、max_locals

max_locals :表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量,u2类型,00 01十进制为1,表示只有一个局部变量
在这里插入图片描述

3.5.3.1.3、code_length

code_length:表示该方法所包含的字节码的字节数以及具体的指令码,具体字节码即是该方法被调用时,虚拟机所执行的字节码,u4类型,00 00 00 05十进制为5,代表虚拟机执行字节码长度、
在这里插入图片描述

3.5.3.1.4、code[code_length]

在这里插入图片描述
在这里插入图片描述
十个长度的十六进制字节码是如何与图片二右侧的助记符相对应上的?

  • 1、点击aload_0会链接到oracel官方网站,可以查找,aload_0所对应的十六进制字节码,aload_0对应2a,aload_0含义是将栈中索引为0的栈针推送到栈顶
    在这里插入图片描述

  • 2、点击 getfield,对应字节码b4,并且有参数,参数为00 02十进制为2,在常量池中值为com/shengsiyuan/jvm/bytecode/MyTest1.a:I,表示获取MyTest1对象中的a返回值为int

  • 3、ireturn对应字节码ac,带有返回值

3.5.3.1.5、exception_table_length

这里存放的是处理异常的信息,构造方法不存储异常信息,u2类型,00 00
在这里插入图片描述

3.5.3.1.6、attributes_count

属性数量,u2类型,00 02十进制为2,代表有两个属性
在这里插入图片描述

3.5.3.1.7 、attribute_info,attribute[attribute_count]
  • 1、LineNumberTable

  • 在这里插入图片描述
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0a十进制10,常量池中对应LineNumberTable,行号表,字节码行号和java程序中的行号对应关系,当程序抛异常时才能指定异常行号

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 06十进制为6

  • 1.3、line_table_table_length:表示有几对映射,u2类型,00 01十进制为1,表示有1对映射,字节码00 00映射java代码00 04行号为4
    在这里插入图片描述
    在这里插入图片描述
    2、LocalVariableTable局部变量表
    在这里插入图片描述
    在这里插入图片描述
    结构与LineNumberTable类似
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0b十进制11,常量池中对应LocalVariableTable,

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 0c十进制为12

  • 1.3、line_table_table_length:表示有几个局部变量,u2类型 ,00 01表示有一个局部变量

  • 1.4、00 00 00 05,表示start_pc开始位置为0,结束位置为00 05值为5,紧接着00表示索引0

  • 1.5、0c对应常量池12位置:this当前对象,只有唯一局部变量this

  • 1.6、00 0d对应常量池13位置:Lcom/shengsiyuan/jvm/bytecode/MyTest1;描述当前对象

  • 1.7、 00 00用于校验检查

4、methods_infot方法表(第三个方法)

4.1、access_flags:

访问控制:u2类型,00 01十进制值为1,表示public

4.2、name_index:

方法名称索引,u2类型,00 10:16,常量池: setA

4.3、descriptor_index

方法描述索引,u2类型,00 11:17,常量池:(I)V:,入参int类型,无返回

4.4、attitudes_count

方法属性个数,u2类型,00 01十进制值为1,表示有1个属性

4.5、attitudes_info

方法属性表,

4.5.1、attitude_name_index

方法属性名称索引,00 09:9,常量池:Code,Code为方法的执行代码,每个方法都存在一个Code属性

4.5.2、attitude_length

u4类型,Code长度,00 00 00 3a十进制为58

4.5.3、info[attitude_length]

占据58个字节长度作为Code的值,该部分代表代码所执行的信息

4.5.3.1、Code_attibute
4.5.3.1.1、max_stack

max_stack表示这个方法运行的任何时刻所能达到的操作数盏的最大深度,u2類型,00 02十进制为2,
在这里插入图片描述

4.5.3.1.2、max_locals

max_locals :表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量,u2类型,00 02十进制为2,表示有2个局部变量
在这里插入图片描述

4.5.3.1.3、code_length

code_length:表示该方法所包含的字节码的字节数以及具体的指令码,具体字节码即是该方法被调用时,虚拟机所执行的字节码,u4类型,00 00 00 06十进制为6,代表虚拟机执行字节码长度、
在这里插入图片描述

4.5.3.1.4、code[code_length]

在这里插入图片描述
在这里插入图片描述
十个长度的十六进制字节码是如何与图片二右侧的助记符相对应上的?

  • 1、点击aload_0会链接到oracel官方网站,可以查找,aload_0所对应的十六进制字节码,aload_0对应2a,aload_0含义是将栈中索引为0的栈针推送到栈顶
    在这里插入图片描述

  • 2、 iconst_1对应字节码04,推送一个int整数1在这里插入图片描述

  • 3、putfield对应字节码b5,紧跟着00 002十进制为2,常量池中:com/shengsiyuan/jvm/bytecode/MyTest1.a:I,该方法将1赋值给a变量,赋值是在构造方法中完成的

  • 4、 return对应字节码b1

4.5.3.1.5、exception_table_length

这里存放的是处理异常的信息,构造方法不存储异常信息,u2类型,00 00
在这里插入图片描述

4.5.3.1.6、attributes_count

属性数量,u2类型,00 02十进制为2,代表有两个属性
在这里插入图片描述

3.5.3.1.7 、attribute_info,attribute[attribute_count]
  • 1、LineNumberTable

  • 在这里插入图片描述
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0a十进制10,常量池中对应LineNumberTable,行号表,字节码行号和java程序中的行号对应关系,当程序抛异常时才能指定异常行号

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 06十进制为6

  • 1.3、line_table_table_length:表示有几对映射,u2类型,00 01十进制为1,表示有1对映射,字节码00 00映射java代码00 05行号为5
    在这里插入图片描述
    在这里插入图片描述
    2、LocalVariableTable局部变量表
    在这里插入图片描述
    在这里插入图片描述
    结构与LineNumberTable类似
    在这里插入图片描述

  • 1.1、attribute_name_index,u2类型,00 0b十进制11,常量池中对应LocalVariableTable,

  • 1.2、attribute_length,属性表属性长度,u4类型,00 00 00 16十进制为22

  • 1.3、line_table_table_length:表示有几个局部变量,u2类型 ,00 02表示有2个局部变量

  • 第一个变量
    1、00 00 00 06,表示start_pc开始位置为0,结束位置为00 06值为6,紧接着00表示索引0
    2、0c对应常量池12位置:this当前对象,只有唯一局部变量this
    3、00 0d对应常量池13位置:Lcom/shengsiyuan/jvm/bytecode/MyTest1;描述当前对象
    4、 00 00用于校验检查

  • 第二个变量
    1、00 00 00 06,表示start_pc开始位置为0,结束位置为00 06值为6,紧接着00表示索引0
    2、05对应常量池5位置:a,第二个局部变量a
    3、00 06对应常量池6位置:I 对变量a的描述int类型
    4、 00 01用于校验检查
    至此为止三个方法分析完毕

十四、当前类的方法信息

sourceFile:
在这里插入图片描述

  • 1、00 01表示一个属性
  • 2、 00 12:18,常量池:SourceFile
  • 3、 00 00 00 02 :2,表示该属性文件占据字节长度
  • 4、 00 13:19,常量池:MyTest1.java
    至此简单文件字节码分析全部结束
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值