详解 JVM 字节码(3)

版本信息

上一次我们分析前 4 个字节为魔数,继续向下数 4 字节为版本号信息(前两个字节表示此版本号,后两个字节表示主版本号)
00 00 00 36 。36 是 16 进制进行换算 3 * 16 + 6 = 54 这里用的 java 的版本号 10.0.1 版本。

 minor version: 0
 major version: 54

常量池

接下来就是常量池,常量池大小是不固定的。

常量池定义与作用

Java 类中定义的很多信息都是由常量池来维护和描述的。而且字节码其他部分都会引用常量池的内容。所以将常量池看成 Java 类资源仓库。
主要存储两类常量

  • 字面量:文本字符串,java 中声明为 final 的常量值
  • 符号引用 :类和接口的全局(包名)限定名,字段和方法的名称和描述符

常量池的结构

  • 常量池数量:占据 2 字节 00 22
  • 常量池数组:常量池数组中不同元素的类型、结构都是不同的。每一种元素第一个数据都是 u1 类型,是标志位,占一个字节。JVM 在解析常量池时,会根据这个 u1 类型获取元素具体信息。
    这里常量池数量 22 16 * 2 + 2 = 34
   #1 = Methodref          #6.#28         // java/lang/Object."<init>":()V
   #2 = String             #29            // basic
   #3 = Fieldref           #5.#30         // com/zidea/Tut.title:Ljava/lang/String;
   #4 = Fieldref           #5.#31         // com/zidea/Tut.courses:I
   #5 = Class              #32            // com/zidea/Tut
   #6 = Class              #33            // java/lang/Object
   #7 = Utf8               title
   #8 = Utf8               Ljava/lang/String;
   #9 = Utf8               courses
  #10 = Utf8               I
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/zidea/Tut;
  #18 = Utf8               getTitle
  #19 = Utf8               ()Ljava/lang/String;
  #20 = Utf8               setTitle
  #21 = Utf8               (Ljava/lang/String;)V
  #22 = Utf8               getCourses
  #23 = Utf8               ()I
  #24 = Utf8               setCourses
  #25 = Utf8               (I)V
  #26 = Utf8               SourceFile
  #27 = Utf8               Tut.java
  #28 = NameAndType        #11:#12        // "<init>":()V
  #29 = Utf8               basic
  #30 = NameAndType        #7:#8          // title:Ljava/lang/String;
  #31 = NameAndType        #9:#10         // courses:I
  #32 = Utf8               com/zidea/Tut
  #33 = Utf8               java/lang/Object

为什么是 33 而不是 34,常量池数组个数等于常量池数 - 1 ,其中 0 暂时不使用,索引为 0 是 JVM 保留常量,这个常量不位于常量池,这个常量对应 null

常量池11种数据类型的结构表

这个表不用记,学会查表就行
tag - U1 表示常量类型

1. java/lang/Object."<init>":()V

0A: 10
对应查表 U1 为 10 是 CONSTANT_Methodref_Info
00 06 (6)index: 指向声明方法的类描述符CONSTANT_Class_Info的索引项
00 1C(对应十进制 28) index: 指向名称及类型描述符 CONSTANT_NameAndType_Info的索引项

#1 = Methodref #6.#28 // java/lang/Object."<init>":()V

  • #6 = Class #33 // java/lang/Object

  • #33 = Utf8 java/lang/Object
    #28 = NameAndType #11:#12 // "<init>":()V

  • #11 = Utf8 <init>

  • #12 = Utf8 ()V
    这里出现许多看似简写的符号,看一看他们都代表什么含义?
    在 JVM 规范中,每个变量/字段都有描述信息,用于描述字段的数据类型,方法的参数列表(数量、类型与顺序)与返回值。
    描述规则基本数据类型和代表无返回值的 void 类型都用一个大写字符来表示,对象类型则使用字符L加对象全局名称来表示。

  • 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。
    描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序存放在一组()之内。

public void setTitle(String title)

编译为字节码(Ljava/lang/String;)V

2. basic

08 标识符对应 CONSTANT_String_Info

  • 00 1D(29) index 指向字符串字面量索引
  • #29 = Utf8 basic
    在 Tut 类将 title 字段赋值为 basic 这个字符串。

3. com/zidea/Tut.title:Ljava/lang/String;

09 标识符对应 CONSTANT_Fieldref_Info

  • 00 05 (5): 指向声明字段的类或者接口描述符 CONSTANT_Class_Info 的索引
  • 00 1E (30): 指向字段描述符 CONSTANT_NameAndType_Info 的索引值
    指向类描述符为 com/zidea/Tut 为字段所属的类
    字段名称和类型 #30 = NameAndType #7:#8
    #7: title 表示字段名称
    #8: Ljava/lang/String 字段类型为字符串
    表示 Tut 类的 String 类型变量 title

4. com/zidea/Tut.courses:I

09 标识符 CONSTANT_Fieldref_Info
00 05 (5)重复就不多解释了,代表类
00 1F (31)

31 = NameAndType #9:#10 // courses:I

  • course 为变量
  • I 为类型 int

以上就结束两个变量的声明

5. com/zidea/Tut

07 对应标识符为 CONSTANT_Class_Info
00 20 (32) 指向全局限定名常量项的索引

32 = Utf8 com/zidea/Tut

这个类全限定名称

6. java/lang/Object

又是 07 大家自己尝试分析

7. title

01 标识符为 CONSTANT_utf8_Info

  • 00 05 length 表示五个字节,title 就是由五个字符组成的。
  • 74 69 74 6C 65 分为 title 五个字符的ASCII码

8. Ljava/lang/String;

  • 00 12 (18) 向后数 18 字节
  • 4C 6A 61 .!...title...Lja
    00000030: 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B(对应字符 Ljava/lang/String;)

9. courses

10. I

...

#33 = Utf8 java/lang/Object

我相信大家已经了回了怎么进行分析,大家可以自己完成。

这两号表示当前的字节码文件是由那个文件编译出来的。

26 = Utf8 SourceFile

27 = Utf8 Tut.java

在字节码使用/代替.分隔符。

32 = Utf8 com/zidea/Tut


如果有想学习java的程序员,可来我们的java学习扣qun:697699179,免费送java的视频教程噢!我每晚上8点还会在群内直播讲解Java知识,欢迎大家前来学习哦。

猜你喜欢

转载自blog.csdn.net/sdssdfh/article/details/89790837
今日推荐