java类文件结构

3 篇文章 0 订阅

我们都知道我们编写的java程序是要经过编译器编译成class文件,然后由java虚拟机执行class文件,来运行程序的。今天我们简单分析一下class文件的结构。

深入理解java虚拟机一书中对class文件时这样描述的:Class文件时一组以8位字节为基础单位的二进制流,各个数据项严格按照顺序紧凑的排列在Class文件中,中间没有添加任何分隔符,这使得整个Class文件中的内容几乎全部是程序运行的必要数据,没有空隙存在。

Class文件格式采用一种类似于C语言结构体的伪结构存储数据,数据结构中只包括无符号数和表两种数据类型。其中无符号数属于基本数据类型,以u1,u2,u4,u8来分别表示1个字节,2个字节,4个字节,8个字节的无符号数。而表是由多个无符号数和其他数据类型构成的复合数据类型。总体来说,Class文件就是一张表,这张表又包含各个数据项的表。

Class文件中包含如下内容和结构:魔数和Class文件版本;常量池;访问标志;类索引,父类索引和接口索引集合;字段表集合;方法表集合;属性表集合。接下来,对他们分别描述。

魔数和Class版本

Class文件的前面4个字节称为魔数,用来确定这个class文件是否是一个能被虚拟机接受的Class文件。紧接着的4个字节用来存储class文件的版本号。

常量池

常量池中主要存储两大数据类型:字面量和符号引用。字面量表示文本字符串,以及声明为final的常量。符号引用包括了三类引用:类和接口的全限定名,字段名称和描述,方法的名称和描述。另外,常量池中的常量的数量是不固定的,所以在常量池的开始位置会放置一个u2类型的数据,代表常量池容量计数池,并且从1开始计数而不是0。

常量池中的每一项常量都是一张表。常量池中一共有14种常量类型,而且每一种常量类型都有各自的表结构。14种常量数据类型,如下图

访问标志位

常量池结束之后是两个字节代表访问标志,这个访问标志用于识别类或接口层面的访问信息。例如:Class是类还是接口,是public的还是private,是否定义abstract等。

类索引、父类索引和接口索引集合

其中前两个都是u2类型的数据,而接口索引集合是u2类型的集合,通过这三项数据来确定这个类的继承关系。类索引和父类索引分别指向一个类型为CONSTANT_Class_info类描述符常量,再通过存储在CONSTANT_Class_info类型中索引值找到定义在CONSTANT_Utf8_info中的字符串值。

字段表集合

字段表集合用于描述类或接口中声明的变量,但是不包括方法内部声明的变量。包括的信息有:字段作用域是public,还是private等的,是实例变量还是类变量,是否可变(声明final)等。这些修饰符都用布尔值表示,有就为true,没有就是false,至于字段的名字,以及属于什么类型,就要引用常量池中的常量来描述。字段集合中不会出现从父类或者超类中继承来的字段,但是有可能添加原本java代码中没有的字段,比如,内部类为了保持对外部类的访问性,会自动添加指向外部类的引用。

方法表集合

方法表集合是对方法的描述,与字段表集合对字段描述方式一样。同样的,从父类或者超类中继承来的方法不会出现在方法表集合中,而且可能会出现代码中没有方法,比如实例构造器<init>方法。java中重载,除了要与原方法具有相同的名称,还必须拥有一个与原方法不同的特征签名,所谓特征签名就是一个方法的各个参数在常量池中符号引用的结合。因为方法的返回值不在这个集合中,所以不能依靠返回值不同来对一个已有方法重载的。

属性集合

在Class文件,字段表,方法表都可以携带自己的属性集合,主要包括Code属性(java程序中方法中的代码经过javac编译之后变成字节码指令存到Code属性内),Exception属性,SourceFile属性(用于记录Class文件的源文件名),ConstantValue属性(通知虚拟机为静态变量赋值,只有static关键字修饰的变量才能使用此项属性),InnerClass属性(记录内部类与宿主类之间的关联)等


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值