为了达到"傻瓜式"的阅读,方便更容易理解,本篇文章结合了两套视频进行总结的。
视频:黑马程序员JVM完整教程、尚硅谷宋红康JVM全套视频
第一篇:JVM 手把手保姆级教程(1/3):内存结构
第二篇:JVM 手把手保姆级教程(2/3):垃圾回收
第三篇:JVM 手把手保姆级教程(3/3):类加载与字节码技术&内存模型
JVM最后一篇了,学的有点累,写的也有点累了。放弃很容易,但坚持到底一定会有所收获。
1. 类文件结构 1.1 字节码源代码经过编译后会产生一个字节码文件*.class,字节码是一种二进制的类文件。它的内容是JVM的指令,而不像C、C++那样编译后直接生成机器码。
解读字节码文件
- 方式一:Notepad++
Notepad++ 下载插件Hex-Editor可以打开*.class文件
- 方式二:Idea编辑器下载可视化插件jclasslib
代码经过编译后,光标放到需要查看的类上,通过 View->Show Bytecode With Jclasslib查看
- 方式三:通过javap指令:jdk自带的反解析工具
根据 JVM 规范,类文件结构如下:
u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count];
| 类型 | 名称 | 说明 | 长度 | 数量 |
|---|---|---|---|---|
| u4 | magic | 魔数,识别Class文件格式 | 4个字节 | 1 |
| u2 | minor_version | 副版本号(小号) | 2个字节 | 1 |
| u2 | major_version | 主版本号(大号) | 2个字节 | 1 |
| u2 | constant_pool_count | 常量池计数器 | 2个字节 | 1 |
| cp_info | constant_pool | 常量池表 | n个字节 | constant_pool_count-1 |
| u2 | access_flags | 访问标志 | 2个字节 | 1 |
| u2 | this_class | 类索引 | 2个字节 | 1 |
| u2 | super_class | 父类索引 | 2个字节 | 1 |
| u2 | interfaces_count | 接口计数器 | 2个字节 | 1 |
| u2 | interfaces | 接口索引集合 | 2个字节 | interfaces_count |
| u2 | fields_count | 字段计数器 | 2个字节 | 1 |
| field_info | fields | 字段表 | 2个字节 | fields_count |
| u2 | methods_count | 方法计数器 | 2个字节 | 1 |
| method_info | methods | 方法表 | 2个字节 | methods_count |
| u2 | attributes_count | 属性计数器 | 2个字节 | 1 |
| attribute_info | attributes | 属性表 | n个字节 | attributes_count |
根据上表按照顺序去对应字节码文件,下图是一个完整的对应详情。前四个字节是魔数,第五、六字节是副版本号等等。
总结一下类文件结构主要包括以下部分:
- 魔数
- Class的文件版本
- 常量池
- 访问标志
- 类索引、父类索引
- 接口索引集合
- 字段表集合
- 方法表集合
- 属性表集合
- 每个Class开头的前四个字节(ca fe ba be)
- 它的唯一作用就是校验字节码文件的格式
- 使用魔数而不使用扩展名来校验文件格式,是出于安全考虑,因为文件扩展名可以随意改动。
- 紧接着魔数后面的四个字节存储的是Class文件版本号。第5、6字节是编译的副版本号(minor_version),第7、8字节是编译的主版本号(major_version)
- 它们共同组成了Class文件的版本号,比如副版本号为m,主版本号为M,那么该Class文件的版本号就是M.m
- 版本号和Java编译器的对应关系如下图:
下图的十六进制34对应的十进制是52,索引JDK可以推断出是1.8版本的。



