Class文件结构神秘的微笑(一)

“利用碎片化的时间,为你精讲局部知识。”

少废话,先来张图看看一个Class文件长什么样

package com.test;

public class TestClass {
	private int m;
	
	public int inc(){
		return m+1;
	}

}

以TestClass.java为例

Javac TestClass.java

编译后,使用WinHex打开:
在这里插入图片描述

1、学习Class文件的必要性:

了解Class文件结构以及能够分析Class文件中每个字节码代表的含义,这对于我们了解JAVA Virtual Machine(Java虚拟机)很有帮助。

2、学习的引导:

刚接触的读者遇到二进制格式的.Class文件概念时会有畏难情绪,其实,Class文件规则真的很简单。

所有格式的文件都有其对应的文件格式,什么位置放置什么长度的什么值的字节,这些都是有统一的规定。JDK为了实现在新版本下也能执行旧版本的class文件,所以会让Class文件结构保持稳定。因此,不用担心学习的速度跟不上技术的更新。

3、Class文件的基础知识

Class文件是二进制文件,8位组成一个字节,也就是8 bits 组成 1 byte,比如00010001这8位,由于二进制并不直观,我们使用16进制来表示,11110001二进制可表示成 F1十六进制,这样更加直观。

Class文件包含“ 无符号数 ” 和“ ” 。没理解没关系,到示例中你就会明白了。

无符号数:可以用来描述数字、索引引用、数量值、按照UTF-8编码构成的字符串值。常有的长度分别是u1(1个字节)、u2(2个字节)、u4(4个字节)、u8(8个字节)。

:可由无符号数和其他表组成。这是一种递归的定义方式,打个比方:个人信息表单中包含了一条一条的信息,好比电话号码、姓名等,同时也可以包含一张亲属联系方式的联系方式表,这样应该就好理解了。

4、Class文件其实是一张表

如下图:
在这里插入图片描述
分析上面这张图;第一列是类型,代表是无符号数还是表,以_info结尾的那一行是表,其余的是无符号数。第二列是名称,代表无符号数和表的具体名称,第三列是数量,无符号数都是一个,表的个数可以是0个或1个及以上,数量一般取决与前一个无符号数的值。

分别看一下名称的含义:(子表的结构没有放出来,之后会详细介绍)

名称含义
Magic魔数,是一种文件标识符、值固定,用来区别于非Class文件。
Minir_version次版本号,很少使用,很少更改,一般也是固定的值。
Major_version主版本号,编译环境的jdk版本决定,有规律。
Constant_pool_count常量池中常量的个数
Constant_pool常量池表,特别注意的是他的数量是1,只是它里面包含的常量数是Constant_pool_count个。
Access_flag访问标志,通过这个标志位可以判断该类的权限大小以及是类还是接口还是其他类型。
This_class存放的本类的常量池引用(常量池引用对应的也就是对应的全限定类名,下同)。
Super_class存放的父类的常量池引用。Interface_count 继承的接口个数。
Interface_count继承的接口个数。
Interfaces继承的接口表,有多少个继承的接口就有多少个表,此表的结构后头介绍。
Fields_count类中字段的个数
Fileds类中字段表,同样,有多少个类字段就有多少个表,此表的结构后头介绍。
Methods_count类中方法的个数
Methods类中方法表,同样,有多少个类方法就有多少个表,此表的结构后头介绍。
Attributes_count属性表个数
Attributes属性表,这里的属性并不存在于类中,而是将一些很长的信息统一归为各种属性放在最后,以便于前面的那些表引用这里。让布局更加整齐一些。

接下来我们就拿一个实列来体验一下吧。

在这里插入图片描述
前4个字节就是魔数:CAFEBABE,固定的。
在这里插入图片描述
接着的2个字节代表次版本号,一般固定位00 00。
在这里插入图片描述
接着的2个字节代表主版本号,我用的是JDK8版本,16进制的34对应10进制的52,JVM规范中规定JDK 1.1版本对应主版本号是45,JDK每增加一个版本则加1。
在这里插入图片描述
接着的2个字段代表常量池中常量的个数。

常量池中含有什么我们不得而知,我们可以通过cmd来查看javap工具为我们解析的常量池:

Javap -verbose TestClass.class

在这里插入图片描述
常量池多是一些字符引用、字面量、类方法接口的符号引用名。

下面看一下常量池表的结构规定如下图:
在这里插入图片描述
在这里插入图片描述
需要说明的是:标志,占用u1(1个字节),通过告诉读取器,接下来这个常量是什么类型。
在这里插入图片描述
比如0A是10进制的10,就是CONSTANT_Methodref_Info常量,每个常量又有自己不同的表结构。CONSTANT_Methodref_Info表包括u1标志、u2类索引、u3方法索引。解析一下上图就是:u1标志(0A)、u2类索引(00 04)、u3方法索引(00 0F),结合之前cmd得出的常量池4索引代表java/lang/Object,16索引代表"": ()V。这个方法是编译器自己添加的,感兴趣的读者可以自己查阅下资料,或者评论区讨论。

常量池的解析就是上面的步骤。下面我贴出常量池中各子表的结构,读者可继续按照我说的步骤自己操作一遍。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

后续未完成的部分将留作下次讲解。

尾巴:以上知识点融入了自己的理解,如果有疑问或不足,欢迎评论区或私信讨论。
参考文献:
《深入理解Java虚拟机:JVM高级特性与最佳实践(第三版)》
作者:周志明
ISBN:9787111641247

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr. 良爷

您每一分的打赏都是对原创的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值