深入理解JVM - 类文件的结构
类文件的结构
Class类文件是以8个字节为单位的二进制流,由魔数、版本号、常量池、类信息、父类信息、接口表、字段表、方法表和属性表组成。下图清晰的展示了Class类文件的结构。
Class类文件示例
预先准备好一段简单的Java代码和编译好的二进制字节流。
Class类文件是如何组成的
接下来会用上述简单的Java代码为示例来讲解Class类文件是如何组成的?
魔数和版本号
魔数
是用来检查字节流是不是Class类文件,占4个字节。Class类文件的魔数是cafebabe
。
查看偏移地址0x00000000-0x00000003,得到魔数是0xcafebabe,可以得出该字节流是一个Class类文件。
版本号
是指Jdk的版本号,占4个字节。前2个字节是次版本号,后2个字节是主版本号。
查看偏移地址0x00000004-0x00000007,得到次版本号是0(=0x0000),主版本号是52(=0x0034),也就是版本号是52.0,对应的是jdk8。
常量池
常量个数
指常量池中有多少个常量,占2个字节。
查看偏移地址0x00000008-0x00000009,得到该常量池中一共有22(=0x17-1)个常量。减1的原因是常量是从1开始计数的。
常量
指名称(类名、字段名、方法名等)或描述符的字面量或符号引用。
字面量
可以理解为不经过翻译的字符串。比如Java文件中的类名Hello字符串;比如字段名a、b、m字符串;比如方法名inc字符串;比如返回类型int字符串;符号引用
可以理解为由标签和索引(指向字面量或标签)组成。比如类和接口的全限定名;比如字段的名称和描述符;比如方法的名称和描述符。
接下来我们看下这22个常量在字节流中是怎样体现的?查找常量就像密码学里根据密码表找到对应的密码一样。首先准备好定义好的17种数据结构,为了节省篇幅,这17种数据结构请读者参考《深入理解Java虚拟机第3版》常量池一节的表6.6。这里仅列出4种数据结构,下图右边部分。
上图左边部分已根据定义好的17种数据结构列出了Hello.class的22个常量项(#号开头的数字),现以第一个常量项为例来进行讲解。
- 第1号常量项的偏移地址0x0000000A的值为10(=0x0a),对应的是
CONSTANT_Methodref_info
标签。根据该标签的数据结构可得,一共占5个字节,第1个字节就是前面说的标签;第2-3个字节表示该方法属于哪个类,这里指向的是第4号常量项;第4-5字节表示该方法的名称和描述符(指返回类型),这里指向的是第19号常量项。 - 第4号常量项的偏移地址0x00000017的值为7(=0x07),对应的是
CONSTANT_Class_info
标签。根据该标签的数据结构可得,一共占3个字节,第1个字节就是前面说的标签;第2-3个字节表示该方法所在类的全限定名,这里指向的是第22号常量项。 - 第22号常量项的偏移地址0x0000009F的值为1(=0x01),对应的是
CONSTANT_Utf8_info
标签。根据该标签的数据结构可得,一共占6个字节,第1个字节就是前面说的标签;第2-3个字节表示方法名的长度,这里的值为16个字节,接下来的16个字节清晰的展示了类的全限定名(java/lang/Object)。 - 第19号常量项的偏移地址0x0000008D的值为12(=0x0c),对应的是
CONSTANT_NameAndType_info
标签。根据该标签的数据结构可得,一共占5个字节,第1个字节就是前面说的标签;第2-3个字节表示该方法的名称,这里指向的是第11号常量项;第4-5字节表示该方法的描述符,这里指向的是第12号常量项。 - 第11号常量项的偏移地址0x0000003F的值为1(=0x01),对应的是
CONSTANT_Utf8_info
标签。与第22号常量项类似,最后清晰的展示了方法名称(<init> ,即构造器)。 - 第12号常量项的偏移地址0x00000048的值为1(=0x01),对应的是
CONSTANT_Utf8_info
标签。与第22号常量项类似,最后清晰的展示了方法描述符(()V ,即void)。
最后通过javap命令让我们更直观的感受下常量池。
类信息和父类信息
类信息由类访问符
、类名索引
和父类名索引
组成,他们各占2个字节。
查看偏移地址0x000000b2-0x000000b3,得到值为0x0021(=0x0001+0x0020),查表可得类访问符为public super。
查看偏移地址0x000000b4-0x000000b5,得到值为3(=0x0003),表示指向第3号常量项(Hello)。
查看偏移地址0x000000b6-0x000000b7,得到值为4(=0x0004),表示指向第4号常量项(java/lang/Object)。
接口表
接口数量
占用2个字节。查看偏移地址0x000000b8-0x000000b9,得到值为0,也就是说该类没有实现相关接口。
接口表
描述了接口相关信息。
字段表
字段数量
占用2个字节。查看偏移地址0x000000bA-0x000000bB,得到值为3(=0x0003),也就是说该类中有3个字段。
字段表
描述了字段相关信息。
接下来我们根据字段表结构来读下Hello.class字节流中的3个字段。
上图中已经标示了字节流中的3个字段(^角开头的数字)。现以第一个字段为例来进行讲解。
- 偏移地址0x000000bC-0x000000bD的值为0x001a(=0x0002+0x0008+0x0010),定义了字段的访问符,查找字段访问符表可知,该字段由private static final修饰。
- 偏移地址0x000000bE-0x000000bF的值为5(=0x0005),定义了字段名称索引,表示指向第5个常量项(a)
- 偏移地址0x000000c0-0x000000c1的值为6(=0x0006),定义了字段描述符索引,表示指向第6个常量项(I,即int)
- 偏移地址0x000000c2-0x000000cB定义了该字段的属性,属性表稍后讲解。
方法表
方法数量
占用2个字节。查看偏移地址0x000000dC-0x000000dD,得到值为2(=0x0002),也就是说该类中有2个方法。
方法表
描述了方法相关信息。
接下来我们根据方法表结构来读下Hello.class字节流中的2个方法。
上图中已经标示了字节流中的2个方法(^角开头的数字)。现以第一个方法为例来进行讲解。
- 偏移地址0x000000dE-0x000000dF的值为0x0001,定义了方法的访问符,查找方法访问符表可知,该方法由public修饰。
- 偏移地址0x000000e0-0x000000e1的值为11(=0x000b),定义了方法名称索引,表示指向第11个常量项(<init> ,即构造器)。
- 偏移地址0x000000e2-0x000000e3的值为12(=0x000c),定义了方法描述符索引,表示指向第12个常量项(()V,即void)
- 偏移地址0x000000e4-0x000000fA定义了该方法的属性,属性表稍后讲解。
最后通过javap命令让我们更直观的感受下方法表。
属性表
ConstantValue属性
一般定义在字段表中。下图展示了ConstantValue属性的数据结构。
在字段表中说过,偏移地址0x000000c2-0x000000cB定义了字段a的属性。
- 偏移地址0x000000c2-0x000000c3的值为1(=0x0001),定义了该字段属性的个数。
- 偏移地址0x000000c4-0x000000c5的值为7(=0x0007),定义了该字段属性名称的索引,表示指向第7个常量项(ConstantValue)。
- 偏移地址0x000000c6-0x000000c9的值为2(=0x0002),定义了该属性的长度,表示该属性一共占用2个字节。
- 偏移地址0x000000ca-0x000000cb的值为8(=0x0008),定义了该属性的值,表示指向第8个常量项(属性值为10)。
Code属性
一般定义在字段表中。下图展示了Code属性的数据结构。
在方法表中说过,偏移地址0x000000e4-0x000000fA定义了<init>方法的属性。
偏移地址0x000000e4-0x000000e5的值为1(=0x0001),定义了该方法属性的个数。
偏移地址0x000000e6-0x000000e7的值为13(=0x000d),定义了该方法属性名称的索引,表示指向第13个常量项(Code)。
偏移地址0x000000e8-0x000000eB的值为29(=0x001d),定义了该属性的长度,表示该属性一共占用29个字节。
偏移地址0x000000eC-0x000000eD的值为1(=0x0001),定义了该方法操作数栈深度。
偏移地址0x000000eE-0x000000eF的值为1(=0x0001),定义了该方法局部变量表大小。
偏移地址0x000000f0-0x000000f3的值为5(=0x0005),定义了方法体的长度。
偏移地址0x000000f4-0x000000f8的值为0x2ab70001b1,定义了方法体的指令,这些指令都可以在虚拟机字节码指令表中查到。
1)读入2a,查表得0x2a对应的指令为aload_0,表示将第0个变量槽中reference类型(指this)推送到操作数栈顶。
2)读入b7,查表得0xb7对应的指令为invokespecial,invokespecial用于调用实例构造器、private方法或者它的父类的方法。读入0001,指向第1个常量项,表示invokespecial调用的是实例构造器。
3)读入b1,查表得0xb1对应的指令为return,表示方法正常结束。偏移地址0x000000f9-0x0000108,依次定义了异常表、LineNumberTable属性,这里不作进一步讲解。
为了节省篇幅,属性表中只介绍ConstantValue属性和Code属性两种比较重要的属性,其他的属性,比如Exceptions属性、SourceFile属性等,有兴趣的朋友可以阅读《深入理解Java虚拟机第3版》属性表一节。
Reference
深入理解Java虚拟机第3版
Java虚拟机原理图解
深入理解JVM - 类文件的结构相关推荐
- Class类文件的结构
2019独角兽企业重金招聘Python工程师标准>>> Class类文件的结构 Class类文件的结构 任何一个Class文件都对应着唯一一个类或接口的定义信息,但反之类和接口并不一 ...
- 详解Class类文件的结构(上)
前言 相信搞Java开发的同学都经常会接触到Class类文件,了解了JVM虚拟机之后也会大量接触到class字节码,那么它到底是什么样的文件?内部由什么构成?虚拟机又是如何去识别它的?这篇文章就来学习 ...
- java怎编写么解析一个类型_DAY3:你必须知道的java虚拟机之类篇——类文件的结构...
马上过年啦,不知道大家今年有没有投资基金股票呢?是赚的盆满钵满还是拍断大腿,可以评论区一起交流交流,秀一秀哈哈,反正我是没来得及上车. 暴富西不可能暴富的啦,打工人嘛几能写写文章啦-记得点赞➕关注呀 ...
- [深入理解Java虚拟机]第六章 Class类文件的结构
在本章关于Class文件结构的讲解中,我们将以<Java虚拟机规范(第2版 )> (1999年发布,对应于JDK 1.4时代的Java虚拟机)中的定义为主线,这部分内容虽然古老,但它所包含 ...
- 深入理解JVM类文件格式
我们知道Java最有名的宣传口号就是:"一次编写,到处运行(Write Once,Run Anywhere)",而其平台无关性则是依赖于JVM, 所有的java文件都被编译成字节码 ...
- 详解Class类文件的结构(下)
本文继续使用上次的Test.class文件,它是由下面单独的一个类文件编译而成的,没有包. 6. 索引(Index) 索引又分类索引.父类索引和接口索引集合,类索引(this_class)和父类索引( ...
- Java Class类文件的结构
基础概念 任何一个 Class 文件都对应着唯一的一个类或接口的信息 Class 文件是一组以字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符.这使得整个 ...
- JVM——类文件结构
1.概述 老师讲过:"计算机只认识0和1,所以我们写的程序需要经编译器译成由0和1构成的二进制格才能由计算机执行".到由于最近10年内虚拟机以及大量建立再虚拟机之上的程序语言如雨后 ...
- 【转】深入理解JVM—JVM内存模型
原文链接 http://www.cnblogs.com/dingyingsi/p/3760447.html#top 深入理解JVM-JVM内存模型 我们知道,计算机CPU和内存的交互是最频繁的,内存是 ...
- 深入理解JVM(1):类加载器
文章目录 一.类加载简介 1.简介 2.Java虚拟机与程序的生命周期 3.类的加载.连接与初始化(类加载的最重要的3个阶段) 3.1加载 3.2连接 3.3 初始化 4.类的使用和卸载(类加载的剩余 ...
最新文章
- html怎么移动文字的位置,css怎么移动文字
- nbiot开发需要掌握什么_包装设计需要掌握什么技巧
- 分段概率密度矩估计_考研数学:高数、线代、概率3科目知识框架梳理
- 小夕说,不了解动态空间增长的程序喵都是假喵(下)
- html%2b怎么转换成加号,Apache mod_rewrite%2B和加号(+)符号
- 常见面试算法:树回归、树剪枝
- unhandled exception in MSDEV.EXE(DEVSHL.DLL) :0xC0000005
- miui9如何不自动杀进程,小米9怎么关闭自动更新 具体操作方法解析
- 【大数据技术】实验4:熟悉Spark基础编程
- 从龟速 11s 到闪电 1s,详解前端性能优化之首屏加载
- Linux内核PWN-基础ROP提权
- 3D数学基础——欧拉角与万向节死锁
- MongoDB之文本搜索
- 理解偏差和方差(Bias-Variance)的Tradeoff
- 计算机打印机共享失败,电脑共享打印连接错误怎么回事 电脑打印共享错误的解决方法...
- AutoJS一文精通AutoJS脚本教程详解
- UCI 数据集 - http://www.mafutian.net/180.html
- 阿里云接口----OSS文件上传
- 交易猫源码搭建+完整版源码
- Source Insight 将UTF-8格式的JAVA文件转换为GB2312格式的JAVA文件