当JVM运行Java程序的时候,它会加载对应的class文件,并提取class文件中的信息存放在JVM的方法区内存中。

Class文件组成

1、Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按顺序紧凑排列在Class文件中,中间没有分隔符。所以Class文件中存储的内容几乎全部是程序运行的必要数据。

2、当遇到占据8位字节以上空间的数据项时,会按照高位在前的方式, 分割成若干个8位字节进行存储。

ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info contant_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];
}

Class文件数据类型

无符号数

1、基本数据类型,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节。

2、无符号数可以用来描述数字、索引引用、数量值和按照UTF8编码构成字符串值。

1、表用来描述有层次关系的的复合数据结构。

2、表是由无符号数或者其他表作为数据项构成的复合数据结构。

3、所有表都以_info结尾。

4、整个class文件本质上就是一张表。

item1:magic(魔数)[u4]:0xCAFEBABE

辨别class文件与非class文件

item2:minor_version、major_version(次、主版本号) [u2,u2]

随着Java技术的发展,class文件的格式会发生变化。版本号的作用在于使得虚拟机能够认识当前加载class的文件格式。从而准确的提取class文件信息。

item3:常量池(constant_pool_count 、constance_pool)[u2,cp_info]

常量池内容

常量池存放两大类常量:字面量(Literal)和符号引用(Synbolic Reference)

一、字面量

1、文本字符串

2、声明为final的常量值

final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量

3、基本数据类型

4、其他

二、符号引用

类和接口的全限定名(Fully Qualified Name)
字段的名称和描述符(Descriptor)
方法的名称和描述符

常量池结构

JVM会将每一个常量构成一个常量表,每个常量表都有自己的入口地址。而实际上在JVM会将这些常量表存储在方法区中一块连续的内存空间中,因此class文件会根据常量表在常量池中的位置对其进行索引。比如常量池中的第一个常量表的索引值就是1,第二个就是2。有的时候常量表A需要常量表B的内容,则在常量表A中会存储常量表B的索引值x。而constant_pool_count就记录了有多少个常量表,或则所有多少个索引值。实际上,常量池中没有索引值为0的常量表,但这缺失的索引值也被记录在 constant_pool_count中,因此 constant_pool_count等于常量表的数量加1。

常量池计数器(constant_pool_count):常量表(cp_info)数量+1。

常量表(cp_info):constant_pool_count-1个。

常量表结构(cp_info)

每个常量表(cp_info) 都会对应记录着class文件中的某中类型的字面量

这14种表有一个共同的特点,就是开始的第一位是一个u1类型的标志位(tag,就是上表中的标志这一列),代表当前这个常量属于哪种常量类型。

字符串常量池:http://www.cnblogs.com/tenghoo/p/jvm_string.html

基本类型常量池:http://www.cnblogs.com/tenghoo/p/jvm_primitive.html

item4:访问标志(access_flags)[u2]  

表明该class文件中定义的是类还是接口,访问修饰符是public还是缺省。类或接口是否是抽象的。类是否是final的。

item5:类索引(this_class) [u2]、父类索引(super_class)[u2]、接口索引集合(inteface_count、interfaces )[u2,u2]

1、Class文件通过这三项数据来确定这个类的继承关系。

2、类索引用于确定这个类的全限定名。

3、父类索引用于确定这个类的父类的全限定名。由于Java语言不允许多重继承,所以父类索引只有一个。

4、除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。

5、接口索引集合就用来描述这个类实现了哪些接口。

6、类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在CONSTANT_Utf8_info类型的常量中的全限定名字符串。

7、对于接口索引集合,入口的第一项:u2类型的数据为接口计数器(interfaces_count),表示索引表的容量。如果该类没有实现任何接口,则该计数器值为0,后面接口的索引表不再占用任何字节。

item6:字段表集合(field_count,fields) [u2,field_info]

1、字段表(field_info)用于描述接口或者类中声明的变量。

2、字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

field_info表格式

access_flags(2byte 访问修饰符)

name_index(2byte 存储字段名的常量表在常量池中的索引)

description_index(2byte 存储字段的所属类型的常量表在常量池中的索引)

attribute_count(2byte 属性表的数量)

attribute (属性)

其中attribute是由多个attribute_info组成。而JVM规范定义了字段的三种属性:ConstanceValue、Deprecated和Synthetic。

item7:方法表集合(method_count、methods) [u2,method_info]

method_count、methods 与字段类似,method_count表明类中方法的数量和每个方法的常量表的索引。methods表明了不同长度的method_info表的序列。

method_info表格式

access_flags(2byte 访问修饰符)

name_index(2byte 存储方法名的常量表在常量池中的索引)

description_index(2byte 存储方法的返回类型和参数类型的常量表在常量池中的索引)

attribute_count(2byte 属性表的数量)

attribute (属性)

其中方法的属性JVM规定了四种:Code,Deprecated,Exceptions,Synthetic。

简单名称:方法名如:fun,字段名如:str1

全限定名:com/mobjia/clazz/TestClass

描述符:

描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。

根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符L加对象的全限定名来表示。

数组类型:每一维度将使用一个前置的“[”字符来描述,如一个定义为“java.lang.String[][]”类型的二维数组,将被记录为:“[[Ljava/lang/String;”,一个整型数组“int[]”将被记录为“[I”。

用描述符来描述方法时,按照先参数列表,后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”之内。

void inc()的描述符为()V
java.lang.String toString()的描述符()Ljava/lang/String;
int indexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,inttargetCount,int fromIndex)的描述符 ([CII[CIII)I

item8:属性表集合(attribute_count、attributes) [u2,attribute_info]

Class文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。

与Class文件中其他的数据项目要求严格的顺序、长度和内容不同,属性表集合的限制稍微宽松了一些,不再要求各个属性表具有严格顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java虚拟机运行时会忽略掉它不认识的属性。为了能正确解析Class文件,《Java虚拟机规范(第2版)》中预定义了9项虚拟机实现应当能识别的属性,而在最新的《Java虚拟机规范(Java SE 7)》版中,预定义属性已经增加到21项。

对于每个属性,它的名称需要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示,而属性值的结构则是完全自定义的,只需要通过一个u4的长度属性去说明属性值所占用的位数即可。一个符合规则的属性表应该满足下表中所定义的结构。

Class实例分析工具

jvm class分析工具:

WinHe十六进制编辑器

https://sourceforge.net/projects/classeditor/files/

http://xuantan.iteye.com/blog/2030651

参考:

http://blog.csdn.net/luanlouis/article/details/39960815

http://blog.csdn.net/a616413086/article/details/52250638

http://hxraid.iteye.com/blog/687660

jvm理论-class文件的更多相关文章

  1. JVM查找类文件的顺序(转)

    配置classpath 根据path环境变量的原理,可以定义一个名为classpath环境变量,将要运行的class文件所在目录定义在该变量中. 例:set classpath=c:\ classpa ...

  2. 获取JVM的dump文件

    获取JVM的dump文件的两种方式 1. JVM启动时增加两个参数: #出现 OOME 时生成堆 dump: -XX:+HeapDumpOnOutOfMemoryError #生成堆文件地址: -XX ...

  3. JVM中class文件探索与解析(一)

    一直想成为一名优秀的架构师的我,转眼已经工作快两年了,对于java内核了解甚少,闲来时间,看看JVM,吧自己的一些研究写下来供大家参考,有不对的地方请指正. 废话不多说,一起来看看JVM中类文件是如何 ...

  4. JVM中class文件探索与解析

    一直想成为一名优秀的架构师的我,转眼已经工作快两年了,对于java内核了解甚少,闲来时间,看看JVM,吧自己的一些研究写下来供大家参考,有不对的地方请指正. 废话不多说,一起来看看JVM中类文件是如何 ...

  5. JVM基础02-class文件

    一.class文件结构 介绍之前,请下载一个Bytecode工具,例如byte code viewer或者Java Bytecode Editor,我用的是后者Java Bytecode Editor ...

  6. Tomcat输出保存JVM GC日志文件

    当系统出现问题时,分析java虚拟机GC日志可以帮助我们定位问题,一般来说, 我们可以通过制定JVM参数使tomcat保存GC日志文件,具体实现如下: Windows下: 找到tomcat的解压目录, ...

  7. JVM及class文件加载问题-学习使人快乐4

    今天看了些粗浅的JVM原理的知识 1.class文件编译过程: 词法分析 语法分析 源码 ---------Token流-------------语法树----------字节码 2.classloa ...

  8. jvm理论-字节码指令

    Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成. 基本数据类型 1.除了l ...

  9. jvm理论-运行时数据区

    三大流行jvm sun HotSpot ibm j9 BEA JRockit Oracle 会基于HotSpot整合 JRockit. jvm运行时数据区 java虚拟机所管理的内存将会包括以下几个运 ...

随机推荐

  1. 关于ubuntu的ssh远程登录的问题

    一. 安装ssh(参考:http://liuyifan789.iteye.com/blog/2068263) sudo apt-get install openssh-server openssh-c ...

  2. UOJ#275. 【清华集训2016】组合数问题 数位dp

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ275.html 题解 用卢卡斯定理转化成一个 k 进制意义下的数位 dp 即可. 算答案的时候补集转化一下 ...

  3. 060 SparkStream 的wordcount示例

    1.SparkStream 入口:StreamingContext 抽象:DStream 2.SparkStreaming内部原理 当一个批次到达的时候,会产生一个rdd,这个rdd的数据就是这个批次 ...

  4. 043 hive数据同步到mysql

    一:意义 1.意义 如果可以实现这个功能,就可以使用spark代替sqoop,功能程序就实现这个功能. 二:hive操作 1.准备数据 启动hive 否则报错,因为在hive与spark集成的时候,配 ...

  5. 2018-03-11 20165235祁瑛《Java程序设计》第二周学习总结

    2018-03-11 20165235祁瑛<Java程序设计>第二周学习总结 教材学习内容总结 第二章要点: 在这一章中我学到了很多东西: (1)布尔类型boolean,布尔类型的赋值只能 ...

  6. 怎样将一个Long类型的数据转换成字节数组

    直接上代码: //先写进去 long n = 1000000L; ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutpu ...

  7. LINQ技术

    转载http://www.cnblogs.com/Dlonghow/p/1413830.html Linq (Language Integrated Query,语言集成查询),是微软公司提供的一项新 ...

  8. 在Idea中添加自定义补全代码设置(Main方法为例)

    一.打开File->setting->Editor->Live Templates 二.注意右边有“+”.“-”号,点击+号选择第二个Template Group...,并输入新组名 ...

  9. 算法进阶面试题07——求子数组的最大异或和(前缀树)、换钱的方法数(递归改dp最全套路解说)、纸牌博弈、机器人行走问题

    主要讲第五课的内容前缀树应用和第六课内容暴力递归改动态规划的最全步骤 第一题 给定一个数组,求子数组的最大异或和. 一个数组的异或和为,数组中所有的数异或起来的结果. 简单的前缀树应用 暴力方法: 先 ...

  10. the secrets

    prime time productions: my life had collepes arround me? i have worked myselft into exhaustion. my f ...