Class文件的基本结构

引导

Class文件的基本结构
Class文件的常量池
Class文件的访问标志,类索引,父类索引,接口索引
Class文件的字段和方法

Class文件的基本结构

我们知道,编写的 .java 源文件会被 java 编译器编译成 .class 文件,它是由字节组成的文件,又叫字节码文件。

那你知道 class 文件里面都存储了哪些数据吗?这里我绘制了 class 文件的 UML 图和基本组成结构。

class文件UML图.png
class文件基本结构.png

魔数

所有 java 编译器编译的 .class 文件的前4个字节都是 0xCAFEBABE,被称为魔数(magic)。

它的作用在于,JVM 在尝试加载某个文件的时候,会先读取文件的前4个字节,判断是否是 0xCAFEBABE;如果是,则 JVM 会将此文件作为 class 文件来加载并使用。

版本号

版本号表示当前 class 文件被哪个版本的 java 编译器编译而成。

  1. 副版本号(minor_version),占用第 5、6 两个字节;
  2. 主版本号(major_version),占用第 7、8 两个字节。

JDK1.0 的主版本号(major_version) 为 45,以后的每个新主版本(major_version)都会在原先版本的基础上加1。

JVM 在加载 class 文件的时候,会读取其主版本号(major_version),然后比较主版本号(major_version) 和 JVM 本身的版本号,如果 JVM 本身的版本号小于 class 文件的主版本号(major_version),JVM 会认为加载不了这个 class 文件,并抛出 java.lang.UnsupportedClassVersionError

举个栗子,这里我用 java11 编译生成 .class 文件,然后使用 java8 运行。

UnsupportedClassVersionError.png

常量池计数器

常量池计数器(constant_pool_count)描述着整个 class 文件的字面量数量。

常量池数据区

常量池(constant_pool)是由若干 cp_info 的结构体组成。它包含 class 文件结构及其子结构中引用的所有字符串常量、 类或接口名、字段名和其它常量。

常量池(constant_pool)数组长度由常量池计数器(constant_pool_count)指定,它们之间满足如下关系。

// 常量池计数器 = 常量池数组长度 + 1
constant_pool_count = constant_pool.length + 1

常量池(constant_pool)数组的索引范围是 [1, constant_pool_count − 1],这里的索引不是从 0 开始的。

将索引为 0 的常量池项空出来是为了满足特定情况下指向常量池索引的数据不引用任何一个常量池项,这种情况下可以将常量池索引设置为0,比如 java.lang.Object 的父类索引(super_class)。

访问标志

访问标志(access_flags)是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性。

一些常见的值以及其含义如下图所示。

access_flags.png
  1. ACC_INTERFACE 表示是接口。如果一个 class 文件有 ACC_INTERFACE 标志,那么也得设置 ACC_ABSTRACT;并且不能设置为 ACC_FINALACC_SUPERACC_ENUM
  2. 注解类型必须带有 ACC_ANNOTATION 标志,如果设置了 ACC_ANNOTATION 标志,ACC_INTERFACE 也必须同时被设置;
  3. ACC_SUPER 标志用于确定该 class 文件里面的 invokespecial 指令使用的是哪一种执行语义。目前 java 编译器应该都会设置这个标志,ACC_SUPER 是为了兼容旧编译器编译 class 文件而存在的;

类索引

类索引(this_class)表示这个 class 文件所定义的类或接口。

类索引(this_class) 的值必须是常量池(constant_pool) 数组中的一个有效索引值,且常量池(constant_pool)数组在此索引处的项必须是 CONSTANT_Class_info 类型的。

父类索引

父类索引(super_class)表示这个 class 文件所定义类或接口的直接父类。

  1. 对于非 java.lang.Object 的类,父类索引(super_class)的值必须是常量池(constant_pool)数组中的一个有效索引值,且常量池(constant_pool)数组在此索引处的项必须为 CONSTANT_Class_info 结构;
  2. 对于 java.lang.Object 类,父类索引(super_class)的值一定是 0;
  3. 对于接口,父类索引(super_class)的值必须是常量池(constant_pool)数组中的一个有效索引值,且常量池(constant_pool)数组在此索引处的项必须是代表 java.lang.Object 类的 CONSTANT_Class_info 结构;

类的直接父类以及所有间接父类的访问标志(access_flag)中都不能带有 ACC_FINAL 标记。

接口计数器

接口计数器(interfaces_count)表示当前类或接口的直接父接口数量。

接口信息数据区

接口信息(interfaces)是一个索引数组,表示当前类或接口的直接父接口信息。

接口信息(interfaces)数组的长度为接口计数器(interfaces_count)的值。数组中每一项必须是常量池(constant_pool)数组中的一个有效索引值,且常量池(constant_pool)数组在此索引处的项必须为 CONSTANT_Class_info 结构。

数组表示的接口顺序和对应的源文件中给定的接口顺序(从左至右)一样,即第一个元素对应的是源文件中最左边的接口。

字段计数器

字段计数器(fields_count)表示当前 class 文件声明的所有字段数量,不包括从父类或父接口继承的字段。

字段信息数据区

字段表(fields)表示当前 class 文件声明的所有字段,不包括从父类或父接口继承的方法。

字段表(fiels)的长度为字段计数器(field_count)的值。数组中每一项都必须是 field_info 结构,表示当前 class 文件中某个字段的完整描述。

方法计数器

方法计数器(methods_count)表示当前 class 文件声明的方法数量,不包括从父类或父接口继承的方法。

方法信息数据区

方法表(methods)表示当前 class 文件声明的所有方法,不包括从父类或父接口继承的字段。

方法表(methods)的长度为方法计数器(method_count)的值。数组中每一项都必须是 method_info 结构,表示当前 class 文件中某个方法的完整描述。

如果方法表(methods)中某一项的 access_flags 既没有设置 ACC_NATIVE 标志,也没有设置 ACC_ABSTRACT 标志,那么它所对应的方法体就应当可以被 JVM 直接从当前类加载,而不需要引用其它类。

属性计数器

属性计数器(attributes_count)表示当前 class 文件的所有属性数量。

属性信息数据区

属性表(attributes)表示当前 class 文件的所有属性。

属性表(attributes)的长度为属性计数器(attribute_count)的值。表中每一项都必须是 attribute_info 结构,描述某个属性的完整信息。

Java 7 规范里,class 文件结构中的属性表(attributes)可以包括下列定义的属性:InnerClassesEnclosingMethodSyntheticSignatureSourceFileSourceDebugExtensionDeprecatedRuntimeVisibleAnnotationsRuntimeInvisibleAnnotations 以及 BootstrapMethods 属性。

  1. 对于支持 class 文件主版本号(major_version)为 49.0 或更高的 JVM,必须正确识别并读取 SignatureRuntimeVisibleAnnotationsRuntimeInvisibleAnnotations
  2. 对于支持 class 文件主版本号(major_version)为 51.0 或更高的 JVM,必须正确识别并读取 BootstrapMethods

Java 7 规范要求任一 JVM 可以自动忽略 class 文件中它不可识别的属性项。

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

推荐阅读更多精彩内容