本文参考书籍:《深刻理解Java虚拟机》有兴趣的同窗也能够经过看书了解更多内容。
最近在读这本书,顺便作下知识整理。在了解了class文件结构后能够更好的了解类的加载机制。若是对此内容已经了解的同窗能够移步:类的加载机制。java
如需转载请注明出处,class文件的结构 。linux
java语言的一句口号你们应该都很熟悉:"Write once, run anywhere." 那是由于Java虚拟机不与任何语言绑定,它只与“Class文件”这种特定的二进制文件格式所关联。 Java虚拟机也不止支持java一种语言。数组
从上图能够看出多种语言经过编译成*.class文件均可以在JVM上运行。 下面让咱们了解一下class文件的结构。安全
注:(此文以JDK1.4为主线讲解)post
首先看一下class文件的基本概念:测试
class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序节凑的排列在Class文件中,中间没有添加任何分隔符,使得整个Class文件中从存储的内容几乎所有是程序运行时的必要数据,没有任何空隙。当遇到须要占用8位以上空间的数据项时,则会按照高位在前的方式分割为若干个8位字节进行存储。this
1,无符号数:属于基本的数据类型,以u一、u二、u四、u8来分别表明一、二、四、8个字节的无符号数,无符号数能够用来描述数字、索引引用、数量值、或者按照UTF-8编码的字符串值。
2,表:由多个无符号数或者其余表做为数据项构成的复合数据类型,全部表都习惯性的以“info”结尾。Class文件本质上就是一张表。
下面是一张普通class文件的表,咱们能够看下表的大致结构和具体内容都有什么。编码
图2中红字标注后面会作具体分析。3d
每一个Class文件的前4个字节称为魔数(Magic Number),它的惟一做用是肯定这个文件是不是一个能被虚拟机接受的Class文件。使用魔数而不使用扩展名来验证是出于安全考虑,由于扩展名能够随意改变。java语言魔数就是:CAFEBABE(十六进制数)。此 魔数也用于后面类加载中的验证。cdn
Class第五、6个字节是次版本号,七、8个字节是主版本号。(主版本号就是咱们常说的JDK1.7或1.8,次版本号就是1.7后面的小版本号。)
常量池能够理解为Class文件的资源仓库。 因为常量池中常量的数量是不固定的,因此在常量池入口须要放置一项u2类型的数据,表明常量池容量计数值(constant_pool_count)。常量池索引从1开始。
如上图6-3所示,魔数后是小版本号和大版本号,后面紧跟着就是常量池入口,入口前两个字节表示了常量池中常量的个数。图中都为十六进制数,0x16就是十进制的22,而常量池计数都是从1开始,不是从0开始,因此这里面表示常量池中索引范围是1~21,而非0~21,因此常量池中共有21项常量。
常量池中主要存放两大类常量:1,字面量。2,符号引用。
接近于Java语言层面的常量概念。如:字符串,final常量等。
属于编译原理方面概念,包括下面三类:
常量池中每一项常量都是一个表,在JDK1.7以前共有14种结构各不相同的表结构数据,1.7以后又额外增长了3种。 这14种表都有一个共同的特色,就是表开始的第一位是一个u1类型的标志位(tag),表明当前这个常量属于哪一种常量类型。
下面咱们来看下这些表的结构。
上面咱们已经说过第九个字节0x16是常量池入口,也是常量池中常量的数量,那么紧接着就是常量池的第一项常量。请看下图。
tag是标志位,区分常量类型;name_index是一个索引,它指向常量池中一个CONSTANT_Utf8_info类型常量,此常量表明了这个类和接口的全限定名。图4中第一个常量的tag为0x07,咱们查看图5中的表来肯定是哪一种常量类型。
常量池紧接着两个字节表明访问标志(access_flags)。 访问标志:类或接口的层次信息,包括:这个Class是类仍是接口;是不是public;是否认义abstract;若是是类的话,是否声明final等。图10表示了访问标志具体表述的全部内容。
能够查找图10中的表测试类访问标志为0x21就是图10中ACC_PUBLIC和ACC_SUPER的结合,可见这个TestClass类就是一个普通的public的java类。
这种方式你们能够联想一下linux的权限码,我感受很相似,例如:chmod 755 + 文件名,755中三位数字分表表示文件所属用户的权限、文件所属组的权限、其余用户权限。4表明读权限,2表明写权限,1表明执行权限。755就是赋予文件全部者读、写、执行权限(4 + 2 + 1 = 7),赋予文件全部者的组读、执行的权限(4 + 1 =5),赋予其余用户也是读和执行的权限(4 + 1 = 5)。是否是与这个access_flags很是类似,用不多的字符表示多个属性。
访问标志后接的下来就是类索引和父类索引,类索引和父类索引都是u2类型数据,接口索引集合是一组u2类型的数据集合。Class文件中由这三项数据来肯定类的继承关系。
接下来就是字段表集合。
字段表(field_info):用于描述接口或者类中声明的变量。
你们能够想一下Java描述字段能够包含哪些信息?
包括信息有:做用域(public、private、protected)、是否static、是否final、是否volatile、是否transient、字段数据类型(基本类型、对象、数组)、字段名称。
理解了上面的字段表,方法表的结构和字段表相似。
看完此篇之后更容易理解:类的加载机制,若是有兴趣的同窗能够继续阅读。
欢迎若有问题欢迎留言。