Java Class文件结构

在了解Java class文件结构之前,我们思考一下如下几个问题:

  1. Windows、Linux、Mac 三大平台上的可执行程序格式一样吗?如果不一样,那是什么原因导致的哪?
  2. png、jpeg等格式的图片在上述三个平台上都能打开,原因是什么?
  3. java文件被编译成class文件,结合Java语法,你觉得class文件中应该包含哪些信息哪?

一. 无关性的基石

Java实现了程序的“一次编写,到处运行”,不管在哪种操作平台上,虚拟机都可以载入和执行同一种字节码文件,这种字节码文件是与平台无关的。
各种不同平台的虚拟机与所有平台都统一使用的程序存储格式--字节码是构成平台无关性的基石。
对虚拟机而言,它是语言无关的,它并不和包括Java在内的任何语言绑定,它只与“class文件”这种特定的二进制文件格式相关联,class文件中包含了Java虚拟机指令集和符号表以及若干其他辅助信息。任一门功能性语言都可以表示为一个能被Java虚拟机所接受的有效的class文件,虚拟机并不关心class的来源是何种语言。

虚拟机提供的语言无关性

二. Class类文件的结构

class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在class文件之中,中间没有添加任何分隔符,这使得整个class文件中存储的内容几乎全部都是程序运行的必要数据,没有空隙存在。
根据Java虚拟机规范的规定,class文件格式采用一种类似C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数
无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值以及按照UTF-8编码构成字符串值。
是由无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个class文件本质上就是一张表,它的数据项如下图所示:

类型 名称 数量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count - 1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count

无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这一系列连续的某一类型的数据被称为某一类型的集合

1. 魔数与class文件的版本

每个class文件的头4个字节称为魔数(Magic Number),它的唯一作用就是确定这个文件是否为一个能被虚拟机接受的class文件,也即是用来确定文件格式,同jpeg、gif等文件格式一样。实际上,很多文件都用Magic Number来标识文件格式。
Magic Number后的4个字节存储的是class文件的版本号:5~6字节是次版本号,7~8字节是主版本号。

2. 常量池

常量池是class文件的“资源仓库”,是class文件结构中与其他项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一。
常量池中常量的数量是不固定的,所以在常量池入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count)。

3. 访问标志

访问标志(access_flags)用于识别一些类或者接口层次的访问信息,包括:这个class是类还是接口,是否定义为public类型,是否定义为abstract类型,是类的话是否被声明为final等。
access_flags中一共有16个标志位可以使用,当前只定义了其中8个,没有使用到的标志位一律为0。

4. 类索引、父类索引、接口索引集合

类索引(this_class)和父类索引(super_class)都是一个u2类型的数据。
接口索引集合(interfaces)是一组u2类型数据的集合。

class文件中由这三项数据来确定这个类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。Java语言不允许多重继承,所以父类索引只有1个。接口索引集合用来描述这个类实现了哪些接口,这些被实现的接口将按implements语句(如果这个类本身是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口索引集合中。

类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在CONSTANT_Utf8_info类型的常量中的全限定名字符串。

对于接口索引集合,入口的第一项--u2类型的数据为接口计数器(interfaces_count),表示索引表的容量。如果该类没有实现任何接口,则该计数器值为0,后面接口的索引表不再占用任何字节。

5. 字段表集合

字段表用于描述接口或类中声明的变量。字段表包含的信息有:

  • 字段的作用域(public、private、protected)
  • 是实例变量还是类变量(static修饰符)
  • 可变性(final)
  • 并发可见性(volatile修饰符)
  • 可否被实例化(transient修饰符)
  • 字段数据类型(基本类型、对象、数组)
  • 字段名称

上述信息中,各个修饰符都是布尔值,要么有某个修饰符,要么没有,适合使用标志位来表示。
字段名称、字段数据类型是无法固定的,只能引用常量池中的常量来描述。

字段表

6. 方法表集合

方法表的内容同字段表的内容一样,它们不同的地方在于访问标志和属性表集合的可选项。比如:volatile和transient关键字不能修饰方法,所以方法表的访问标志中就没有ACC_VOLATILE和ACC_TRANSIENT标志;synchronized、native、strictfp和abstract关键字可以修饰方法,所以方法表的访问标志中增加了ACC_SYNCHRONIZED、ACC_NATIVE、ACC_STRICTFP和ACC_ABSTRACT标志。
方法的定义通过访问标志、名称索引、描述符索引表表达,而方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为“Code”的属性里面。

方法表

7. 属性表集合

在Class文件、字段表、方法表中都可以携带自己的属性表(attribute_info)集合,用来描述某些场景专有的信息。
与Class文件中其他的数据项目要求严格的顺序、长度和内容不同,属性表集合的限制稍微宽松一些,不再要求各个属性表具有严格顺序,并且只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java虚拟机运行时会忽略它不认识的属性。Java SE 7中预定义了21项属性,每种属性都有自己的表结构。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  •  每一个class文件都对应着唯一一个类或者接口的定义信息,但是相对地,类或者接口并不一定都必须定义在文件里(比如...
    SunnyMore阅读 6,053评论 0 1
  •  在《JAVA CLASS的文件结构(规范篇)》中我们基本完整的描述了class的文件结构规范,这一篇我们以一个实...
    SunnyMore阅读 1,006评论 0 1
  • Java代码必须要被编译成class文件后,虚拟机才能够加载运行,要搞清楚Java的类加载机制,首先必须要理解Cl...
    云飞扬1阅读 9,144评论 2 61
  • 同步容器 1、同步容器的思路:隐藏状态、对象访问加锁2、同步容器单个操作都是线程安全的,但是复合操作不是线程安全的...
    春天里的布谷鸟阅读 1,051评论 1 1
  • 妈妈说,六月的天是孩子的脸,说变就变。刚进六月,天气就变得调皮起来,上午还是晴空万里,下午却又变得忧郁起来,起先是...
    微笑的贝壳儿阅读 229评论 0 0