37+38+39+40-Java字节码+常量池+描述符+字节码整体结构

Java字节码文件结构剖析+Java字节码常量池深入剖析+透彻分析常量池常量结构与描述符+Java字节码常量池深度剖析与字节码整体结构分解

运行Classpy : cmd gradlew run

一、字节码内容定义:
  • 1.使用javap -verbose命令解析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息、类变量与成员变量等信息
  • 2.魔数:所有的.class字节码文件的前4个字节码都是魔数,魔数值为固定值:0xCAFEBABE
  • 3.魔数之后的4个字节为版本信息,前两个字节表示minor version(次版本号),后两个字节表示major version(主版本号),这里的版本号为00 00 00 34,换算成十进制,表示次版本号为0,主版本号为52。所以,该文件的版本号为:1.8.0。可以通过java -version命令来验证这一点。【如果JVM的版本号是1.7 ,而字节码文件是1.8,那么,会报不支持的版本号错误。】
  • 4.常量池(constan pool):紧接着主版本号之后的就是常量池入口。一个Java类中定义的很多信息都是由常量池维护和描述的,可以将常量池看作是Class文件的资源仓库,比如说Java类中定义的方法与变量信息,都是存储在常量池中。**常量池中主要存储两类常量:字面量与符号引用。**字面量如文本字符串,Java中声明为final的常量等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等。
  • 5.常量池的总体结构:Java类对应的常量池主要由常量数量与**常量数组(常量表)**这两部分组成。
    • 常量池数量紧跟在主版本后面,占据2个字节;;常量池数组则紧跟在常量池数量之后。
    • 常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都是不同的,当然长度也就不同。但是,每一种元素的第一个数据都是一个u1类型,[什么是u1l类型:该字节是一个标志位,占据一个字节]。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。
    • 值得注意的是,常量池数组中元素的个数 = 常量池数 - 1(其中0暂时不适用),目的是满足某些常量池索引值的数据在特定情况下需要表达『不引用任何一个常量池』的含义;**根本原因在于,**索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应null值;所以,常量池的索引从1而非0开始。
  • 6.在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;
  • 7.对于数组类型来说,每一个维度使用一个前置的 [ 来表示,如:int[]被记录为 [I ,String[] [] 被记录为 [[Ljava/lang/String;
  • 8.用描述符描述的方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之内,如方法:String getName(int id ,String name)的描述符为:(I , Ljava/lang/String;) Ljava/lang/String;
二、Class文件中的数据类型表:

在这里插入图片描述

  • 上面的表中描述了11中数据类型的结果,其实在jdk1.7之后又增加了3种:
    • CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info。这样一共是14种
三、Java字节码整体结构

在这里插入图片描述

注意:对于字节码来说,类的方法是可以不包含方法的,因为一定要清楚,JVM规范和JAVA规范是两套规范。

对于JVM规范来说,字节码文件可以不包含方法;但是,对于JAVA规范来说(即从Java预语言的角度来说,所生成的字节码必须要包含方法的),JVM所生成的字节码是必须要包含方法的!!!

1.javap jvm/bytecode/MyTest1
E:\Program Files (x86)\IdeaProject\jvmbytecode\out\production\jvmbytecode>javap jvm/bytecode/MyTest1
Compiled from "MyTest1.java"
public class jvm.bytecode.MyTest1 {
  public jvm.bytecode.MyTest1();
  public int getA();
  public void setA(int);
}

2.javap -c jvm/bytecode/MyTest1
E:\Program Files (x86)\IdeaProject\jvmbytecode\out\production\jvmbytecode>javap -c  jvm/bytecode/MyTest1
Compiled from "MyTest1.java"
public class jvm.bytecode.MyTest1 {
  public jvm.bytecode.MyTest1();
    Code:
       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

  public int getA();
    Code:
       0: aload_0
       1: getfield      #2                  // Field a:I
       4: ireturn

  public void setA(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #2                  // Field a:I
       5: return
}
3.javap -verbose jvm/bytecode/MyTest1
E:\Program Files (x86)\IdeaProject\jvmbytecode\out\production\jvmbytecode>javap -verbose  jvm/bytecode/MyTest1
Classfile /E:/Program Files (x86)/.../jvm/bytecode/MyTest1.class  //class文件位于什么地方
  Last modified 2019-12-19; size 471 bytes                  //什么时候修改的
  MD5 checksum 8a3245b061d879e973d07b7eb89537c3             //MD5校验核
  Compiled from "MyTest1.java"										//从什么文件编译出来的
public class jvm.bytecode.MyTest1  //类的名字
  minor version: 0       //小版本 					** 00 00 
  major version: 52      //大版本				   ** 00 34
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:           //常量池               ** 00 18 
   #1 = Methodref     #4.#20   // java/lang/Object."<init>":()V  ** 0A 00 04 00 14
   #2 = Fieldref      #3.#21   // jvm/bytecode/MyTest1.a:I       ** 09 00 03 00 15 
   #3 = Class         #22      // jvm/bytecode/MyTest1           ** 07 00 16
   #4 = Class         #23      // java/lang/Object				  ** 07 00 17
   #5 = Utf8          a							   ** 01 00 01 61
   #6 = Utf8          I							   ** 01 00 01 49
   #7 = Utf8          <init>						** 01 00 06 3C 69 6E 69 74 3E
   #8 = Utf8          ()V						   ** 01 00 03 28 29 56
   #9 = Utf8          Code							** 01 00 04 43 6F 64 65
   **  01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65             
   #10 = Utf8         LineNumberTable 
   **  01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65
   #11 = Utf8         LocalVariableTable     
   #12 = Utf8         this							** 01 00 04 74 68 69 73
   **  01 00 16 4C 6A 76 6D 2F 62 79 74 65 63 6F 64 65 2F 4D 79 54 65 73 74 31 3B 
   #13 = Utf8         Ljvm/bytecode/MyTest1;
   #14 = Utf8         getA                   ** 01 00 04 67 65 74 41
   #15 = Utf8         ()I                    ** 01 00 03 28 29 49
   #16 = Utf8         setA                   ** 01 00 04 73 65 74 41
   #17 = Utf8         (I)V 						** 01 00 04 28 49 29 56
   #18 = Utf8         SourceFile					** 01 00 0A 53 6F 75 72 63 65 46 69 6C 65
   #19 = Utf8         MyTest1.java		** 01 00 0C 4D 79 54 65 73 74 31 2E 6A 61 76 61
   #20 = NameAndType  #7:#87:名字索引,8:描述符的索引】 // "<init>":()V  ** 0C 00 07 00 08
   #21 = NameAndType  #5:#6          // a:I           ** 0C 00 05 00 06
   ** 01 00 14 6A 76 6D 2F 62 79 74 65 63 6F 64 65 2F 4D 79 54 65 73 74 31
   #22 = Utf8         jvm/bytecode/MyTest1
   ** 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74
   #23 = Utf8         java/lang/Object
{
  public jvm.bytecode.MyTest1();
    descriptor: ()V         //描述符
    flags: ACC_PUBLIC       //标记  
    Code:						 //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 3: 0
        line 4: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Ljvm/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 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Ljvm/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 11: 0
        line 12: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Ljvm/bytecode/MyTest1;
            0       6     1     a   I
}
SourceFile: "MyTest1.java"
MyCat.class的16进制:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值