深入理解java虚拟机--Class文件结构

本文详细介绍了Java Class文件的结构,包括魔数、版本号、常量池、访问标志、字段表、方法表和属性表集合。常量池包含了字面量和符号引用,方法表集合描述了类和接口的变量与方法,属性表集合则包含如Code、ConstantValue等重要属性。字节码指令是方法体代码的字节码表示。通过对Class文件的理解,有助于深入掌握Java虚拟机的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是class文件

Class文件是一组以8个字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用8个字节以上空间的数据项时,则会按照高位在前[2]的方式分割成若干个8个字节进行存储。
这种伪结构中只有两种数据类型:“无符号数”“表”,分别以(u1、u2、u4、u8)和_info结尾来表示。

2.类文件中包含哪些结构

①魔数(确定这个文件是class文件)–4字节
②版本号–4字节
③常量池–不固定
④访问标志–2字节:是类还是接口,是否虚类,是否public…满足的限定条件做 “|” 运算
⑤类索引、父类索引、接口索引集合–不固定:类索引(全限定名)、父类索引(全限定名)各两字节,接口索引集合(2字节接口计数器+…)
⑥字段表集合–不固定
⑦方法表集合–不固定
⑧属性表集合–不固定

2.1.常量池中包含哪些内容

①容量计数值–u2(从1开始)
②字面量或符号引用(每一项以u1类型标志位开始)
下图为u1类型标志位含义
标志位类型所代表的含义
17种数据类型的结构见深入理解jvm p310

2.2.字段表集合构成

字段表(field_info)用于描述接口或者类中声明的变量。Java语言中的“字段”(Field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量

(下图为字段表结构)
字段表结构

①访问标志
②简单名称
③描述符
④属性表计数
⑤属性表

简单名称、全限定名、描述符分别指的什么
全限定名:包含类路径的类名
简单名称:方法名inc()–>inc,字段m->m
描述符:描述字段的数据类型、方法的参数列表(数量、类型以及顺序)和返回值

在这里插入图片描述

对于数组类型,每一维度将使用一个前置的“[”字符来描述,如一个定义为“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,int targetCount,int fromIndex)的描述符为“([CII[CIII)I”。

在Java语言中字段是无法重载的,两个字段的数据类型、修饰符不管是否相同,都必须使用不一样的名称,但是对于Class文件格式来讲,只要两个字段的描述符不是完全相同,那字段重名就是合法的。

2.3.方法表集合

与属性表基本相同。但是方法里的代码放到了属性表集合中“Code”属性里。
在这里插入图片描述

如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。但同样地,有可能会出现由编译器自动添加的方法,最常见的便是类构造
器“()”方法和实例构造器“()”方法

特征签名(重载):特征签名是指一个方法中各个参数在常量池中的字段符号引用的集合,也正是因为返回值不会包含在特征签名之中,所以Java语言里面是无法仅仅依靠返回值的不同来对一个已有方法进行重载的。但是在Class文件格式之中,特征签名的范围明显要更大一些,只要描述符不是完全一致的两个方法就可以共存。也就是说,如果两个方法有相同的名称和特征签名,但返回值不同,那么也是可以合法共存于同一个Class文件中的。

2.4.属性表集合

在这里插入图片描述
①Code属性表:java程序方法体里面的代码经过Javac编译器处理之后,最终变为字节码指令存储在Code属性内。下图为code属性表结构
在这里插入图片描述
code属性表中最重要的就是code属性,用于描述代码

为什么没有定义局部变量的类里args_size至少为1?
在任何实例方法里面,都可以通过“this”关键字访问到此方法所属的对象。这个访问机制对Java程序的编写很重要,而它的实现非常简单,仅仅是通过在Javac编译器编译的时候把对this关键字的访问转变为对一个普通方法参数的访问,然后在虚拟机调用实例方法时自动传入此参数而已。因此在实例方法的局部变量表中至少会存在一个指向当前对象实例的局部变量,局部变量表中也会预留出第一个变量槽位来存放对象实例的引用

②ConstantValue属性:static+final+基本类型或string=用constantvalue来赋值

对非static类型的变量(也就是实例变量)的赋值是在实例构造器()方法中进行的;而对于类变量,则有两种方式可以选择:在类构造器()方法中或者使用ConstantValue属性

③受检异常属性
④源码文件名称属性
⑤内部类属性

3.字节码指令

(转载)字节码指令详见字节码指令集介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值