class类文件结构

前言

我们都知道java是一种基于jvm编译执行的语言,java文件编译成class文件,jvm只与Class文件这种特定的二进制文件格式所关联,任何能够编译成class文件结构的语言都可在jvm上运行如Scala,Groovy,Clojure等。

通常一个Class类文件都对应一个类和接口的定义信息,但是类和接口不一定定义在class文件里,也可以通过类加载器直接生成

class文件是由字节为基础单位的二进制流,各个数据项严格按照顺序紧凑排列在class文件中,顺序,数量,字节序都被严格按照位置存储

class文件格式如图

此处输入图片的描述

magic(魔数)和版本 class文件头4个字节为魔数,作为jvm进行身份识别的标志,为16进制的OxCAFEBABE;第5个和第6个字节是次版本号,第7和第8是主版本号,在这里低版本的jvm会拒绝执行超过版本号的class文件,这也是为什么每个新版本的jdk兼容以前版本jdk原因

常量池

常量池中存放两大类常量

javap工具可以输出class文件中的常量表信息

访问标志 访问标志主要描述了类的一些信息

此处输入图片的描述

类索引,父类索引,接口索引 主要用来确定类的继承关系,表示该类继承的类和实现的接口

字段表 用于描述接口或类中声明的变量,不包含局部变量 如图 此处输入图片的描述

字段表不会列出从父类继承来的字段,但可能会列出原本java中不存在的字段,如内部类对外部类实例的字段

方法表 此处输入图片的描述 可以看到基本和字段表是差不多的结构,除了属性表集合和访问标志的不同

属性表 此处输入图片的描述 此处输入图片的描述

java虚拟机执行字节码是基于栈的体系结构

异常属性是个属性表同一级的属性,主要作用是列举出方法中可能抛出的受检查异常

此处输入图片的描述 number_of_exceptions项表示方法可能抛出异常数量;exception_index_table表示每一种受检查异常,指向常量池汇总的索引

用于描述java源码行号与字节码行号之间关系。我们平常的日志中抛异常时出现的行号,以及debug时的断点位置都来源此

此处输入图片的描述 line_number_table_length表示line_nubmer_info数量,line_nubmer_info含有start_pc和line_number数据项,分别表示字节码行号和java源码行号

用于描述栈帧中局部变量表中变量和java源码中定义的变量之间的关系,我们通过ide编写代码是方法的参数名称就来源于此

此处输入图片的描述

local_ variable_ info中的start_pc,length数据项,分别表示局部变量生命周期开始的字节码偏移量和作用范围长度;name_ index 和 descriptor_ index表示局部变量的名称的常量索引和局部变量描述符;index表示局部变量在栈帧局部变量表中slot位置

LocalVariableTypeTable是泛型引入后用来作为泛型类型的特征说明

此处输入图片的描述 inner_ class_ info_ index 和 outer_ class_ info_ index分别表示内部类和外部类的符号引用 inner_ name_ index和inner_ class_ access_ flags表示内部类名称索引,内部类访问标志