详解 JVM 字节码(3)

作者: zidea | 来源:发表于2019-05-03 18:12 被阅读5次
jvm

版本信息

上一次我们分析前 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

相关文章

  • JVM

    JVM 基础-类字节码详解 多语言编译为字节码在 JVM 运行 Java 字节码文件-- Class文件的结构属性...

  • 详解 JVM 字节码(3)

    版本信息 上一次我们分析前 4 个字节为魔数,继续向下数 4 字节为版本号信息(前两个字节表示此版本号,后两个字节...

  • JVM知识精粹

    1.jvm执行字节码文件 流程:jvm通过类加载器加载字节码文件----字节码校验器---翻译字节码(解释执行,反...

  • Java并发机制的底层原理

    Java程序执行:Java代码→Java字节码→字节码被类加载器加载到JVM里,JVM执行字节码→转化为汇编指令在...

  • Java并发机制的底层实现原理

        Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为...

  • 详解 JVM 字节码 (1)

    在开始分析 class 字节码前我们先补一补一些基础知识,帮助我们更好地了解 jvm 是如何执行字节码的。大家可能...

  • 详解 JVM 字节码(2)

    什么是字节码,为什么需要字节码编译 JVM 编译成机器码, 我们看一看 Java 编译过程 java 源码 编译为...

  • 详解 JVM 字节码(Four)

    访问标志 访问标志信息包括该 Class 文件是类还是接口,是否被定义成 public,是否是 abstract,...

  • 详解 JVM 字节码(8)

    字节码的执行方式,程序执行有两种是编译执行和解释执行,JIT 编译产生本地代码生成机器码来执行。现在的 JVM 解...

  • 详解 JVM 字节码(5)

    今天进入最关键也是最重要部分方法表,也是有一定难度。 定义方法访问标记00 01 :表示一个 public 方法,...

网友评论

    本文标题:详解 JVM 字节码(3)

    本文链接:https://www.haomeiwen.com/subject/yilonqtx.html