Pearhair带你学JVM第0章——反读class文件

Pearhair带你学JVM第0章——反读class文件

前言

我们知道JAVA文件经过编译生成class文件,由类加载器加载到JVM虚拟机进行执行,要想对JVM有一个更好的理解,我们需要先对class文件进行解析学习。
视频参考:B站河北王校长


一、环境准备

使用notepad++对编译后的class文件进行读取,获取到里面十六进制的数据。

1.安装Notepad++,对java代码进行编译生成class文件

下面是类的声明和定义。

// An highlighted block
1  package jvmClass;
2   
3  public class jvmClass {
4    private  String name;
5
6   public String getName() {
7       return name;
8    }
9}

2.安装完成之后,点击插件,安装HEX-Editor插件.

在这里插入图片描述

3.使用Notepad++打开class文件,打开后按下快捷键Ctrl+Alt+Shift+H,用16进制方式查看。

在这里插入图片描述
数据显示,class文件一共有21行,每一行有十六列数据。

二、进行解析十六进制数据

1.魔数

通过查询class文件结构表,我们可以看出
在这里插入图片描述

表1 class文件结构表

前四个字节是魔数.(代表文件是class文件)
CA FE BA BE

2.主次版本号

通过继续查表可以看出,接下来的是两个字节的次版本号,两个字节的主版本号。
00 00 次版本号
00 34 主版本号

**十六进制的34转化为十进制后是52,查询JDK版本号对应的表可知,52代表当前JDK的版本用的是JDK8**

在这里插入图片描述

3.常量池计数器

通过继续查表可以看出,接下来的是两个字节的常量池容量计数池。
00 13
常量池计数器19(实际存放了18个常量)

3.1 第一个常量

0A 10 查表可知,代表的是CONSTANT_Methodref_info(类中方法的符号引用)
00 04指向第四个常量 --------> java/lang/object
//一旦有一个类需要初始化,就必须首先初始化他的父类
00 0F指向第15个常量 --------> CONSTANT_NameAndType_info

在这里插入图片描述

3.2 第二个常量

09 CONSTANT_Fieldref_info(字段的符号引用)
00 03 指向第三个常量 --------> jvmclass/jvmclass(全包名+类名)
00 10 指向第16个常量 --------> CONSTANT_NameAndType _info

3.3 第三个常量 jvmclass/jvmclass(全包名+类名)

07 CONSTANT_Class_info(类或者接口的符号引用)
00 11 指向第17个常量

3.4 第四个常量Object

07 CONSTANT_Class_info(类或者接口的符号引用)
00 12 指向第18个常量

3.5 第五个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用)
00 04 长度,字符串的长度
6E 61 6D 65 -->代表的是name

3.6 第六个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用)
00 12 长度18的字符串

4C 6A 61 76 61 2F 6C 61 61 6E 2F 53 74 72 69 6E 67 3B //Ljava.lang.string;
//L开头代表后边直接跟着我们的类的描述符

3.7 第七个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用)
00 06长度为6的字符串
3C 69 6E 69 74 3E //方法 初始化的,java文件编译为class文件,jvm为我们自动生成

3.8 第八个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用)
00 03长度为3的字符串
28 29 56 ()V 方法的返回值为 void (方法的返回值)

3.9 第九个常量

//第9个常量01
00 04
43 6F 64 65 // Code属性(方法里面都有code属性)

3.10 第十个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用)
00 0F 一共15个长度的字符串
4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 // LineNumberTable 代表代码的行号
//抛出异常,需不需要看异常代码?代码是第几行啊?打印的错误信息里边就包含了吧?

3.11 第十一个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 07
67 65 744E616D65 //getName(方法名称)

3.12 第十二个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 14 长度为 20
28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B // Ijava/lang/string;

3.13 第十三个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 0A 长度为 10
53 6F 75 72 63 65 46 69 6C 65 // SourceFile(源文件标识)

3.14 第十四个常量

01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 0D 13个长度
6A 76 6D 43 6C 61 73 73 2E 6A 61 76 61 // jvmclass.java 真正的文件名称啊

3.15 第十五个常量

//第15个常量(有一个常量,代表了init名称和void名称)
0C CONSTANT_NameAndType_info
00 07指向第7个常量
00 08指向第8个常量void返回值

3.16 第十六个常量

//第16个常量 (有一个常量,他的名称叫name,他的类型叫 Ljava/lang/string;)
0C CONSTANT_NameAndType _info
00 05 指向第5个常量 name
00 06指向第6个常量 Liava/lang/string;

3.17 第十七个常量

//第17个常量
01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 11 17个长度的字符串
6A 76 6D 43 6C 61 73 73 2F 6A 76 6D 43 6c 61 73 73 // jvmclass/jvmclass(全包名+类名)

3.18 第十八个常量

//第18个常量
01 CONSTANT_UTF8_info(类或者接口的符号引用) 字面量(看上去是啥就存放啥)
00 10 16个长度的字符串
6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 // java/lang/object

4.访问标志、类索引、父类索引

十六进制数据从class文件结构表(表1)可以看到,查询访问标志表,可以得出
00 21 //访问标志 ACC_PUBLIC +ACC_SUPER
00 03 //类索引 指向第三个常量 jvmclass
00 04 //父类索引指向第三四个常量

在这里插入图片描述

访问标志表

5.接口索引计数值、接口索引

00 00 没有实现任何接口,所以为0

6.字段表计数器

00 01 字段表计数器 有一个字段
00 02 private
00 05 指向第五个常量 name
00 06 指向第六个常量 Ljava/lang/string ===>推导出来private String name;
00 00 没有其他属性

7.方法表计数器

00 02方法表计数器有两个方法(init,getName)
第一个方法:
00 01 public 方法
00 07指向第7个常量 init
00 08指向第8个常量 void
00 01有一个属性,(Code属性)
00 09指向第9个常量 Code属性
00 00 00 1D 长度是1D=29
00 01最大栈深度1
00 01最大局部变量表槽的数量1
00 00 00 05代码编译后所生成的JVM指令码的长度
2A //aload _0 指令,将我们的第一个属性压入栈顶
B7 //invokespecial,调用所引用对象的构造方法
00 01 //调用第一个方法(init)
B1 //return

00 00 异常信息为空
00 01code属性是有一个的
00 0A 指向第10个常量 LineNumberTable
00 00 00 06 属性长度为6
00 01 有一个属性
00 00 字节码的行号
00 03 代码的行号

第二个方法:
00 01 public 方法
00 0B指向11个常量 getName
00 0C指向第12个常量 Ijava/lang/string
00 01有一个属性,(Code属性)
00 09指向第9个常量 Code属性
00 00 00 1D 长度是1D=29
00 01最大栈深度1
00 01最大局部变量表槽的数量1
00 00 00 05代码编译后所生成的JVM指令码的长度
2A //aload _0 指令,将我们的第一个属性压入栈顶
B4 //getfield指令 这个方法就是为了获取name并且return
00 02 //指向第二个常量 Ijava/lang/string; name
B0 //arereturn, 返回name对象这个引用
00 00 异常信息为空
00 01code属性是有一个的
00 0A 指向第10个常量 LineNumberTable
00 00 00 06 属性长度为6
00 01 有一个属性
00 00 字节码的行号
00 07 代码的行号

8.属性表计数器

00 01 属性表计数器,一个属性
00 0D 指向第13个常量 SourceFile
00 00 00 02 2个长度的属性
00 0E指向第14个常量 jvmClass.java

三、总结

无非就是通过表的对应,找到class文件的结构和对应关系。

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值