[jvm虚拟机]class类文件结构

本文详细介绍了Java编译后的.class文件的基本概念、结构及其组成部分,包括魔数、版本信息、常量池等内容。

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

Technical--Documentation

共享技术文档

项目简介

为为日常工作和学习的总结。

技术文档主站简介

主站文档是我在前人的脚步上对研发的学习和总结纪录,在以后的日子里,我会将自己研发工作中所可能遇见问题和心得在这里纪录下来,公开的分享。世界的存在很美好,开源的存在很精彩。从今天起,我便借助开源的力量,向改变人类的生活方式这条路迈进。

点击这里直接进入为为技术文档主站,或者访问 https://weiwei02.github.io/Technical--Documentation/
与文档配套的 Technical--Documentation项目的地址是 https://github.com/weiwei02/Technical--Documentation

*.class文件介绍

一般来讲.class文件是.java文件在编译器编译后生成的jvm能够运行的文件,*.class文件又常被称为字节码文件。java在创始之初,就提倡“一次编写,处处运行的概念”,在当今编程圈中这个概念早已不是什么特例。java通过将开发人员所编写的java代码编译成class文件,然后由jvm虚拟机在执行时将不分平台的class文件中的字节码,再翻译成机器码,交给硬件执行。java就是靠jvm虚拟机的这个设计来实现与平台无关的特性的。class文件不但与硬件平台和操作系统无关,也和具体的编程语言无关,就目前来说,如函数式编程语言scala与Groovy都可以通过自己的编译器将源代码编译成class文件,在jvm上运行。
综合来讲,class文件有以下两点特性:

  • 与硬件和操作系统平台无关
  • 与源码所使用的编程语言无关

class类文件的结构

每一个class文件都唯一对应着java类或接口枚举等定义信息,但类不一定都定义在class文件中,类可能是由类加载器动态生成的。

class文件所以被称之为字节码据我猜测可能是因为class文件以8位(1字节)为单位进行存储的二进制信息。字节码中各个数据项目严格按照顺序紧凑的排列,中间没有任何分割符。在需要存储整型或浮点型这些大于8位的数据项目时,则会使用Big-Endian的字节序进行存储,将最高位字节放在地址最低位,最低位字节放在地址最高位。

class文件格式采用表来存储数据,表中有无符号数和表两种数据类型。对于这两种数据类型说明如下:

  • 无符号数: 无符号数是基本的数据类型,可以用来表示数字、索引引用、数量值或者按照UTF-8编码构成的字符串。如u1,u2,u4,u8分别代表1,2,4,8个字节字节的无符号数。
  • : 表是由多个无符号数或者其它表作为数据项所组成的复合数据结构,表用于描述层次关系和复合的数据结构,整个class文件就是一张表。通常表以 _info 结尾。如表1就是一个class的表示例。
类型名称数量
u4magic1
u2minor_version1
u2major_version1
u2constant_pool_count1
cp_infoconstant_poolconstant_pool_count - 1
u2asscess_flags1
u2this_class1
u2super_class1
u2interfaces_count1
u2interfacesinterfaces_count
u2fields_count1
field_infofieldsfields_count
u2methods_count1
method_infomethodsmethod_count
u2attributes_count1
attribute_infoattributesattributes_count

表 1 class文件格式

class文件的顺序和格式必须严格实现按照上述规则,否则jvm将不能识别执行。

Magic Number 魔数

魔数是一个和文件后缀名相似的用于文件格式识别的约定,一般规定文件内容开头的前几个字节为文件的魔数。不同于文件后缀名很容易被用户以重命名的方式进行更改,文件的魔数作为识别手段可以更安全的确定文件的可用性。

class文件使用前4个字节作为魔数,来确定.class文件是否是一个能够被虚拟机识别的文件,其值是 0xCAFFEBABE 。

版本

class文件的第5-6个字节代表的可执行该class文件的目标虚拟机的最低次版本号(Minor Version),第7-8个字节是主版本号(Major Version)。java虚拟机可以运行比当前虚拟机版本号低的class文件,拒绝运行版本号不合法,或比自己版本高的class文件。JDK1.1的版本号是45,之后的每个大版本发布都把主版本号加1,如JDK1.2主版本号是46,JDK8的版本号是52。
JDK在编译java文件是可以通过 javac -target 1.6 ...命令来指定编译后的class文件可以在1.6的虚拟机版本上运行。

常量池

常量池是class文件中第一个表类型的数据项目,常量池是class文件中的资源仓库,是class文件结构中与其它项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一。

class文件里紧随版本之后的数据项是常量池,由于常量池的数量是不固定的,所以在常量池的数据项之前放置的有一个u2类型的数据,代表常量池的大小。常量池大小的初始值是1,如常量池的大小的数据如果显示的是10,就代表该class文件中有9个常量。
常量池中主要存放两大类常量:Literal(字面常量)、Symbolic Reference(符号引用常量)。字面常量类似于java中常量的概念,如文本字符串、final关键字所声明的常量等。而符号引用常量则是编译中的概念,主要包括以下三种类型的常量。

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

class文件中不会保存各个方法或字段在内存中的布局信息,而是在虚拟机加载class文件时进行动态的连接。虚拟机在运行class文件时从常量池中获取对应的符号引用,再在创建类或者运行时解析连接到具体的内存地址当中。
常量池中的每一个常量都是一个表,在JDK8中有14种表结构的常量表。如表 2 所示。

类型标识描述
CONSTANT_utf8_info1UTF-8编码的字符串
CONSTANT_Integer_info3整形字面量
CONSTANT_Float_info4浮点型字面量
CONSTANT_Long_info长整型字面量
CONSTANT_Double_info双精度浮点型字面量
CONSTANT_Class_info类或接口的符号引用
CONSTANT_String_info字符串类型字面量
CONSTANT_Fieldref_info字段的符号引用
CONSTANT_Methodref_info10类中方法的符号引用
CONSTANT_InterfaceMethodref_info11接口中方法的符号引用
CONSTANT_NameAndType_info12字段或方法的符号引用
CONSTANT_MothodType_info16标志方法类型
CONSTANT_MethodHandle_info15表示方法句柄
CONSTANT_InvokeDynamic_info18表示一个动态方法调用点

表 2 常量池数据项目类型表

这14种常量结构表开始的第一个字节都是一个u1类型的标识位,其值就是表2中每项常量表类型所对应的标识列的值,代表当前常量属于哪种常量类型。这14种常量类型各自有自己不同的表结构,详情如表 3 所示。

常量项目类型描述
CONSTANT_Utf8_infotagu1值为1
lengthu2UTF-8编码的字符串占用的字节数
bytesu1utf-8编码的字符串
CONSTANT_Integer_infotagu1值为3
bytesu4按照Big-Endian存储的int值
CONSTANT_Float_infotagu14
bytesu4按照Big-Endian存储的float值
CONSTANT_Long_infotagu15
bytesu8按照Big-Endian存储的long值
CONSTANT_Double_infotagu16
bytesu8按照Big-Endian存储的long值double值
CONSTANT_Class_infotagu17
indexu2指向全限定名常量项的索引
CONSTANT_String_infotagu18
indexu2指向字符串常量的索引
CONSTANT_Fieldref_infotagu19
indexu2指向声明字段的类或接口描述符CONSTANT_Class_info的索引值
indexu2指向CONSTANT_NameAndType_info的索引值
CONSTANT_Methodref_infotagu110
indexu2指向声明方法的类描述符CONSTANT_Class_info的索引值
indexu2指向CONSTANT_NameAndType_info的索引值
CONSTANT_InterfaceMethodref_infotagu111
indexu2指向声明方法的接口描述符CONSTANT_Class_info的索引值
indexu2指向CONSTANT_NameAndType_info的索引值
CONSTANT_NameAndType_infotagu112
indexu2指向该字段或方法名称常量的索引值
indexu2指向该字段或方法描述符常量的索引值
CONSTANT_MethodHandle_infotagu115
reference_kindu1值必须1~9,它决定了方法句柄的的类型。方法句柄类型的值表示方法句柄的字节码行为
reference_indexu2对常量池的有效索引
CONSTANT_MethodType_infotagu116
description_indexu2对常量池中方法描述符的有效索引常量池在该处的索引必须是CONSTANT_Utf8_info的结构,表示方法的描述符。
CONSTANT_InvokeDynamic_infotagu118
bootstap_method_attr_indexu2对当前class文件中引导方法表的bootstap_methods[]数组的有效索引
name_and_type_indexu2对当前常量池的有效索引,常量池在此处必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述。

表 3 常量池中14中常量的结构总表

在表 3 中可以看到class文件所支持的所有的常量的结构信息,另外由于class中的类名、方法、字段都要用CONSTANT_Utf8_info型的常量来描述名称,所以CONSTANT_Utf8_info的最大长度也是java中类名、方法名或字段的最大长度65535,如果超出这个最大长度,便会无法编译。

访问权限标识

引用

在写作本文的过程中引用了以下资料,为为在此深深谢过以下资料的作者。

  1. 《The Java Virtual Machine Specification》
  2. 《深入理解Java虚拟机:JVM高级特性与最佳实践/周志明著.——2版.——北京:机械工业出版社,2013.6》

关于

本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到 weiwei02@vip.qq.com

from weiwei.wang 20170625

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值