java class文件布局架构

本文介绍了Java的.class文件格式,包括魔数、版本号、常量池、访问标志、类索引、父类索引和接口索引集合等关键组成部分。这些内容揭示了.class文件如何实现平台无关性,以及在JVM上的运行机制。

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

c语言将.c文件编译生成与硬体相关的二进制机器指令,问题在于不同的系统中的机器指令不同,所以c语言所编写的程序可移植性差。而java号称一次编写,到处运行(Write Once,Run Anywhere),java语言将.java文件经过编译成固定格式的.class文件,并在JVM上执行来达到这种平台无关的效果。也就是说:JVM不与任何包括java在内的语言做绑定,JVM只与固定格式的二进制class文件关联。这也正是为什么Clojure、Groovy、JRuby、Scala这么多新性语言都是在JVM上运行的原因,因为他们只要最后编译生成class文件即可。那么.class文件具体结构是怎么样的呢?

Class文件格式

数据类型

class是一个二进制文件,其中的数据都用无符号数表示,基本数据类型有4种:u1,u2,u3,u4。分别代表1、2、4、8四种字节的无符号数,这些无符号的数字用来表示各种字面量、符号引用、数值量或者utf-8构成的字符串值。除了上述四种基本数据类型还有一种复合数据类型:表。我们用_info结尾表示表结构,表是多个基本数据类型组合而成,用来表示多个层次上并列的关系的数据。实际上整个class文件也可以理解为一张表。

一个class文件的格式

类型名称(CN)名称数量
u4魔数magic number1
u2次版本号minor_version1
u2主版本号major_version1
u2常量池数量constant_pool_count1
cp_info常量池表constant_poolconstant_pool_count-1
u2访问标志access_flags1
u2类索引this_class1
u2父类索引super_class1
u2接口索引数量interfaces_count1
u2接口索引interfacesinterfaces_count
u2字段数量fields_count1
field_info字段表fieldsfields_count
u2方法数量methods_count1
method_info方法表methodsmethods_count
u2属性数量attributes_count1
attribute_info属性表attributesattributes_count

因为class文件是二进制文件,其中没有任何的多余修饰标记,所以任何一处错误都会使得整个文件发生错位,上述文件格式被严格的规定不允许任何的变动。

魔数 magic number

class文件使用魔数来标识它可以被java虚拟机识别。事实上魔数不是java发明的,很多格式的文件都会用魔数来标识文件类型,因为相比较容易被用户修改的用户名,魔数是编辑在二进制文件内部的难以修改。在class文件中采用的魔数是0xCAFEBABY。

版本号 version

在魔数后的四个字节是版本号,五六个字节是次版本号,七八个字节是主版本号。这四个字节合起来准确的表达了当前class所需的最低jdk版本。版本号和jdk的版本之间的关系如下(主要几个版本):

jdk版本class文件中版本号
JDK 1.1845.3
JDK 1.5.0_1149.0
JDK 1.6.0_0150.0
JDK 1.7.051.0

上面简单的列出了几个对应关系,并不全面但是我们需要知道的是,版本号主要大概在45.3-(50+)左右。

常量池 constant_pool

因为常量的数量是不固定的,所以在class文件中常量池首先由一个constant_pool_count来表示所有常量的数量。其后跟随一个共有constant_pool_count-1个数据信息的表。比如常量数量为8,则说明有7个常量(索引为1~7),之所以没有0索引是因为我们把0索引空出来表示“不引用任何常量池”的含义。这也反映出常量池计数constant_pool_count最小值为1,表示不引用任何常量池。

我们将字面量符号引用两大类信息放入常量池中,作为常量信息存储起来。字面量表示文本字符串、声明为final类型的常量值。而符号引用则属于编译原理方面的概念,符号引用通常包括三大方面:

  1. 类和接口的全限定名
  2. 字段的名称和描述符
  3. 方法的名称和描述符

java在编译的过程中并没有c和c++的“连接”步骤,每个类之间并不能互通有无。java的处理方法是,在虚拟机加载class文件时将每个类有关类名、类方法名、字段名等信息的符号引用存放在方法区的常量池中,等到类被创建或者使用时解析将符号引用替换为直接引用。或许这么多的名词让你迷茫,总之简单的说,就是我们先用一个叫做符号引用的东西占位,当我们真正需要使用该类时在用正主把这个占位的替换掉,而这些所有的引用方式都存在于方法区的常量池中。

下面列举了14种常用的常量池的项目类型,包括字面量和引用两种:

这里写图片描述

常量池中14种常量项结构总表:
这里写图片描述

这里写图片描述

访问标志 access_flags

访问标志很简单,是用来表示此类的一些修饰符信息的。在常量池结束后,紧跟的两个字节信息就是访问标志,访问标志会唯一的标识出此类是否为public、是否定义为abstract、是否为final等信息。

类索引 this_class

类索引是一个u2类型数据,用来确定此类的全限定名。类索引通过指向一个类型为Constant_Class_Info来表述类的全限定名。

父类索引 super_class

父类索引也是一个u2类型数据,用来确定此类的父类的全限定名。父类索引通过指向一个类型为Constant_Class_Info来表述此类的父类的全限定名,如果此类是Object类,则没有父类,该u2数据为0。

接口索引集合 interfaces

接口索引集合由一个接口索引数量interfaces_count来做计数。后面的interfaces_count个u2数据表示接口的索引全限定名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值