本文从以下方面描述类文件结构:
(一)class文件的结构
一、魔数与class文件版本
二、常量池
三、访问标志
四、类索引、父类索引、接口索引集合
五、字段表集合
六、方法表集合
七、属性表集合
(一)class文件的结构
1、概述
class文件是以8位字节为基本单位二进制流,各个结构严格按照顺序排列起来,中间没有任何分割符。 当遇到要占用8位字节以上的空间数据时,则会按照高位在前的方式分割成若干个字节进行存储。
2、class文件中的数据类型
Java虚拟机规范规定,Class文件的格式采用一种类似C语言的结构体的伪结构存储。
有两种数据类型:
(1)无符号数
(2)表
2.1、无符号数
属于基本数据类型,以u1,u2,u4,u8分别表示1字节,2字节,4字节,8字节的无符号数;
无符号数用来描述:数字,索引引用,数量值,或者按照UTF-8编码的字符串值。
2.2、表
表是有多个无符号数,或者其他表作为数据项构成的复合数据类型,所有表习惯以“_info”结尾;
2.3、图示class文件格式
一、魔数与class文件版本
1、概述
class文件的开始4字节表示为魔数(Magic Number)。开始四字节值为0xCAFEBABE。
2、作用
用于确定该文件是否是一个能被虚拟机加载的Class文件。
3、次版本、主版本
紧随魔术之后的u2为次版本(minor_version),之后的u2两个字节为主版本(major_version)
4、class文件的版本号
二、常量池
1、概述
在次版本、主版本之后的数据项为常量池,常量池与class文件中其他项目关联最为密切,也是占用class文件最大的数据项之一,也是class文件中第一个出现表结构的数据。
2、常量池池容量计数值(constant_pool_count)
常量池的入口放置一个u2类型的数据,代表常量池容量计数值(constant_pool_count)。池容量计数值是从1开始的,0项有特殊意义(0项,为了满足某些指向常量池的索引值的数据在特定的情况下需要表达“不引用任何一个常量池项目”)。
2.1、注意
Class文件中只有常量池是从1开始计数,其他集合类型,诸如:接口索引集合、字段表集合、方法表集合、等计数从0开始。
3、常量池存放的常量类型
(1)字面量(Literal)
(2)符号引用(Symbolic References)
3.1、字面量
类似于java中的常量,如:文本字符串、被声明为final的常量值。
3.2、符号引用
属于编译原理方面的概念,包括如下3类常量:
(1)类和接口的全限定名(Full Qualified Name)
(2)字段名称和描述符
(3)方法名称和描述符
3.2.1 全限定名、简单名称、描述符
(1)全限定名:包名与类名组成的字符串
(2)简单名称:没有类型和参数修饰符的方法或字段名称
(3)描述符:
① 用于描述:字段的数据类型,方法的参数列表(包括参数类型,数量,顺序)以及方法返回值;
②描述符规则:8个基本数据类型以及无返回值的void都用一个大写字母表示,见下图。对于对象类型来说用字符大写L加对象的全限定名表示,如:Ljava/lang/String;
③数组表示:一维数组如:int[]表示为[I,二维数组java.lang.String[][]表示为[[Ljava.lang.String
④描述符用于描述方法参数时,按照先参数列表,后返回值的顺序描述。如方法void fun(),表示为
()V,java.lang.String toString(),表示为 ()Ljava.lang.String
3.2.2、描述符表示含义图
4、常量池中的项目类型
常量池的每一项常量都是一张表,共有11项目数据各不相同的表结构数据,11中表结构数据都有一个共同点,开始位置都是u1类型的标志位(tag,取值1-12,缺少标志2数据类型),tag标志位表示当前的常量属于那种常量类型,11中常量类型的含义见下图:
4.1、11中数据类型结构总表
三、访问标志(access_flags)
1、概述:
紧随常量池之后的u2类型的数据代表访问标志(access_flags)。
2、作用:
识别类或接口的访问信息,包括,class为类或接口,是否定义为public、是否定义为abstract;如果为类是否声明为final。
3、访问表示的含义表
4、说明
access_flag共有32个标志位可以使用,当前只定义了8个,没有用到的标志位都为0。
例如:用到了 ACC_PUBLIC(0x0001)以及ACC_SUPER(0x0020), 0x0001 | 0x0020 = 0x0021(呈现在字节码中文件的16进制数),所以其他几项标志位都为0。
四、类索引、父类索引、接口索引集合
1、概述
类索引(this_class)和父类索引(super_class)都是一个u2的数据类型,而接口索引集合(interfaces)是一组u2类型的数据集合,class文件通过上述数据类型确定继承关系。这些类型的数据按顺序排列在访问标志(access_flags)之后。
1.1、类索引(this_class)
用于确定类的全限定名。
1.2、父类索引(super_class)
用于确定这个类的父类的全限定名。java不支持多继承,除了java.lang.Object之外,所有的类都有父类,所以父类索引不为0。
1.3、接口索引集合(interfaces)
用于描述类实现了那些接口,这些实现的接口(如果类本身是接口,则为多继承extends)将按照implements语句后的接口顺序从左到右排列在接口索引集合中。
2、说明
(1)类索引(this_class)和父类索引(super_class)引用u2类型的索引值表示,它们指向一个类型为CONSTANTS_Class_info的描述符常量,通过CONSTANTS_Class_info类型中的常量索引值可以找到定义在CONSTANTS_Utf8_info类型的常量中的全限定名字符串。
(2)接口索引集合,第一项为一个u2类型的接口计数器(interfaces_count),表示索引表的容量。
五、字段表集合(fields)
1、概述
字段表(fields_info)用于描述类或接口中的变量。
字段(fields)包括,类变量和实例变量,不包括方法内部声明的变量。
1.1、描述一个字段包括的信息:
①字段的作用域(public 、private、protected);
②类变量后者是实例变量(static);
③是否为常量final;
④并发可见性volatile是否强制从内存读写;
⑤可否序列化(transient);
⑥字段的数据类型(基本数据类型、数组、对象)
1.2、对于字段的修饰符都是boolean值,适合使用标志位来表示,对于字段的数据类型、字段的名字不确定,只能应用常量池中的常量来表示。
2、字段表结构
字段访问标志(access)
3、说明
(1)紧随访问标志是两项索引值:name_index、description_index。都是对常量池的引用,分别代表着字段的简单名称和方法的描述符。(前面章节已经解释过描述符)。对于description_index之后的attribute_info信息,在后续的章节介绍。
(2)字段表集合集合中不会列举出从父类中继承来的字段。但可能会出现代码中不存在的字段,比如内部类保持对外部类的访问,会自动添加指向外部类的实例字段。
(3)java中字段无法重载,字段名称不能重名。对于字节码而言,两个字段的描述符(描述字段的数据类型)不一致,字段名称相同是合法的。
六、方法表集合(method_info)
1、方法表结构
方法的访问标志(access_flags)
2、特征签名
java代码中方法的特征签名只包括了方法的名称、参数顺序、参数的类型,而字节码文件中特征签名还包括方法的返回值及受查异常表。
3、说明
(1)volatile、transient关键字不能修饰方法,因此访问标志中没有上述两种标志。
(2)java方法中的代码,存放在属性表集合中一个名为“code”的属性里面,后续介绍属性表。
(3)如果父类的方法在子类中没有被重写,方法表集合中不会出现来自父类的方法信息(所见即所得,只针对该类文件中出现的方法进行编译)。同样,可能会出现编译器自动添加方法,典型的为类构造器“<clinit>"和实例构造器"<init>"方法
(4)Java中方法的重载,除了与原方法名称一样,还必须拥有一个与原方法不同的特征签名,返回值不会包括在特征签名之内,java中不能依靠返回值不同对方法重载。
(5)class文件中,两个方法同名,同特征签名,方法的返回值不同,可以共存于一个class文件中。
七、属性表集合
属性表(attribute_info):class文件中字段表,方法表可以带有自己的属性表集合,用于描述某些场景的专有信息。
虚拟机规范定义的属性:
对于上述属性的名称,则需要从常量池中引用一个CONSTANT_Utf8_info类型的常量表示,而属性值的结构则是完全自定义的。
7.1 Code属性
java方法体中的代码经过javac编译之后,最终的字节码指令存储在Code属性内。Code属性出现在方法表的属性集合之中,并不是所有的方法都有该属性,比如说:接口,抽象类中的抽象方法。
1、code属性
code属性的结构:
(1)attribute_name_index是指向CONSTANT_Utf8_info型的常量的索引,常量值固定为“Code”;
attribute_length指示了属性值的长度,属性名+属性值=u6字节,所以整个code属性减去6字节为属性值的长度;
(2)max_stack:操作数栈(Oprand Stacks)深度的最大值。方法执行的任意时刻,操作数栈都不会超过这个深度。虚拟机运行时需要根据这个值来分配栈帧中操作数栈的深度。
(3)max_locals:代表局部变量所需的存储空间。max_locals单位是slot。
slot是虚拟机为局部变量分配内存所使用的最小单位。1slot为32位。
(4)code,code_length:用于存储java源程序编译后生成的字节码指令。
code_length为u4类型的长度值,理论上最大值可以达到2的32次方-1,虚拟机规范中规定方法不允许超过65535条字节码指令,如果超过了该限制,javac编译器会拒绝编译。
code属性为class文件中的一个重要的属性,如果把一个java程序中信息一分为二,java代码(code,方法体里的java代码)和元数据(Metadata,包括类、字段、方法及其他信息)两部分。code属性则用于描述代码,所有其他数据项用于描述元数据。
(5)exception_info:异常表信息
异常表中有四个字段:start_pc行到end_pc行(不包含end_pc行),出现了catch_type或其子类型异常,则跳转到handler_pc行继续处理。
如果,catch_type的值为0,代表任何异常情况都要转向到handler_pc处进行处理。
2、Exceptions属性
该Exceptions属性是在方法表中与Code属性平级的一项属性。Exceptions属性列出的是可抛出的受检查的异常(编译时期的异常),也就是方法上声明的throws关键字后面列出的异常。
3、LineNumberTable属性
该属性用于描述java源码行号与字节码行号之间的对应关系。该属性并不是运行时的必须属性。
4、LocalVariableTable属性
用于描述栈帧中局部变量表中的变量与java源码中定义变量的关系,运行时非必须的属性。
5、SourceFile属性
描述生成class文件的源码文件的名称。该属性为可选属性。
6、ConstantValue属性
该属性通知虚拟机为静态变量自动赋值。
对于实例变量赋值是在实例构造器<init>方法中进行的;
类变量两种方式赋值:
①类构造器<client>方法中进行。
②使用constantvalue属性来赋值。
如果final,static同时,修饰一个变量则为常量,并且该常量类型的为基本数据类型或者是字符串类型,就生成ConstantValue属性来进行初始化;如果变量未被final修饰,并且为非基本类型以及字符串类型,则选择在<clinit>方法中初始化。
7、innerclass属性
描述内部类与外部类之间的关联。
上述内容参考自 周志明 《深入理解虚拟机》一书。。。
相关推荐
Java虚拟机中的class类文件的知识,个人整理大的class类文件结构.xmind,有什么问题及时反馈。
首先,让我们来看一下`class类文件结构.png`这张图片。它可能展示了一个清晰的视觉表示,列出了Class文件的各个组成部分,如魔数(Magic Number)、版本号、常量池(Constant Pool)、访问标志(Access Flags)、...
Java 类文件结构是Java虚拟机(JVM)执行字节码的基础,它的核心部分就是类文件,其中包含了关于类和接口的各种元数据。类文件的结构严格定义,以确保跨平台的兼容性。这里我们将详细探讨类文件结构中的常量池、常量...
类文件结构示例,在深入浅出JVM博文中进行演示。如果无关,无需下载。
JVM的指令由一个字节长度、代表着某种特定操作含义的数字(成为操作码)以及跟随其后的零至多个代表此操作所需参数(操作数)而构成。JVM采用面向操作数栈而不是寄存器架构,所以大多只有一个操作码。
Java 类文件结构是Java虚拟机(JVM)执行的基础,它包含了构成Java程序的所有必要信息。Class文件是一种二进制格式,由8位字节组成,数据紧密排列,没有额外的分隔符,确保高效存储。Class文件由一系列的数据项组成...
《JVM系列之一:深入理解类文件结构》 Java虚拟机(JVM)是Java程序的核心执行环境,它负责解释和执行字节码。本文将详细剖析JVM中的类文件结构,这是理解Java程序运行机制的基础。 首先,每个Java源代码文件编译...
0001 ani文件数据结构以及分解ani文件的图像的代码. 0002 bmp文件数据结构.txt 0003 FLV文件数据结构以及读取其脚本信息的代码.txt 0004 gif文件数据结构.txt 0005 ico文件数据结构以及制作特大图标的代码.txt ...
PE 文件结构与 ELF 文件结构详解 在计算机世界中,文件格式是程序员和开发者需要了解的重要知识点之一。PE 文件结构和 ELF 文件结构是两种常用的文件格式,分别是 Windows 操作系统和 Linux 操作系统上的程序文件。...
### Class文件结构浅析 #### 一、引言 在深入了解Class文件的结构之前,我们需要明确Class文件在Java生态系统中的重要地位。Java程序被编译器编译后生成的`.class`文件,实际上是字节码文件,它们是Java虚拟机...
### MIDI文件结构简介 #### 一、MIDI文件概述 MIDI(Musical Instrument Digital Interface,乐器数字接口)文件是一种存储音乐信息的标准格式,广泛应用于电子乐器、音乐制作软件及移动设备等领域。这类文件并不...
深入理解JVM之Class类文件结构详解 Java虚拟机(JVM)是一种运行Java字节码的虚拟机器,Class文件是JVM执行Java程序的基础。Class文件结构是JVM的核心组件之一,对于Java开发者来说,理解Class文件结构是非常重要的...
树形结构之文件结构 简单代码,如何打开文件时在界面以树形方式显示子目录和文件
在IT领域,了解不同文件的数据结构对于开发、分析和处理这些文件至关重要。下面将详细讨论标题和描述中提及的15种文件的数据结构,并提供一些VB6代码示例。 1. **MID文件数据结构**:MIDI(Musical Instrument ...
这两个文件都是DICOM SR类型的实例,可能分别代表当前状态和先前状态的结构化报告数据。它们包含的信息可能包括患者的病史、检查过程、观察结果、诊断结论等。为了理解这些文件的具体内容,我们需要使用DICOM查看器...
DBF文件结构主要由以下几个部分组成: 1. **文件头(Header)**:文件开头的部分,包含关于整个文件的基本信息,如文件创建日期、记录数量、字段数量、字段定义等。文件头通常为32个字节。 2. **字段头(Field ...
标题中的"PE文件结构详细图pdf"指的是一个关于Portable Executable (PE) 文件格式的详细图解文档。在Windows操作系统中,大多数可执行文件、动态链接库(DLLs)和其他可加载模块都采用PE文件格式。这个PDF文档很可能...
DXF(Drawing Exchange Format)文件结构是一种开放标准的数据交换格式,主要用于二维和三维绘图。DXF文件允许不同的CAD(计算机辅助设计)软件之间的数据交换,比如AutoCAD,保证了绘图信息能够被不同平台和设备所...
在深入理解BMP文件结构之前,我们需要知道它是一种未压缩的图像格式,这意味着文件大小通常较大,但优点是图像质量不受压缩影响。 **BMP文件头** BMP文件头由两部分组成:File Header(文件头)和InfoHeader(信息...