深入理解JVM系列(一)类文件格式

本文介绍Java虚拟机的类文件格式。每个类文件都包含一个类或接口的定义。虽然类或接口不需要有字面上包含在文件中的外部表示(例如,因为类是由类装入器生成的),但我们口头上将类或接口的任何有效表示称为类文件格式。

java文件从编码到执行

image.png

1、首先我们有个x.java文件,通过javac命令编译成x.class文件
2、执行java命令将x.class由ClassLoader加载到内存里
3、通常我们在写代码的时候用到的java类库也会被加载到内存中
4、调用字节码解释器或JIT即时编译器进行解释或编译
5、编译完之后由执行引擎通过os的硬件执行

通常java都是使用解释和编译混合模式,非常常用的代码就会由JIT(即时编译器)编译,下次再执行的时候就不要解释器再一句一句的解释执行,效率会高很多,执行引擎可以直接交给操作系统调用,但是不是所有的代码都由JIT编译,这样就不能跨平台了,所以java使用混合模式。


image.png

JVM和语言无关

JVM和java并不是强绑定的,JVM只跟class格式的文件有关系,只要可以编译出符合class规范的文件,都可以在JVM上运行,所以JVM是定义了一种规范。目前可以运行在JVM上的语言有很多,比如Scala、groovy等等。


image.png

类文件结构

类文件由单一的类文件结构组成:

ClassFile {
    u4             magic; 
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

类文件结构中的项如下:

  1. magic(魔数)
    每个Java class 文件的前4个字节被称为他的魔数(magic number):0x CAFEBABE 。魔数的作用在于,可以轻松的分辨出java class文件和非java class 文件。如果一个文件不是以0xCAFEBABE 开头的,那他肯定不是java class文件。

  2. minor_version 和 major_version
    minor_version和major_version项的值是这个类文件的主版本号和次版本号。主版本号和次版本号一起决定类文件格式的版本。如果一个类文件的主版本号为M,次版本号为M,则我们将其类文件格式的版本表示为M. M。因此,类文件格式的版本可以按字典顺序排列,例如,1.5 < 2.0 < 2.1。比如java8就是52.0其中major_version就是52,minor_version就是0。

  3. constant_pool.count 和 constant_pool
    class 文件中,魔数和版本号后面的是常量池。constant_pool是一个结构表,它代表了各种字符串常量,类和接口名,字段名,以及在类文件结构及其子结构中引用的其他常量。每个constant_pool表项的格式都由它的第一个“tag”字节表示。constant_pool表的索引从1到constant_pool_count - 1。 常量池中的类型如下:

    入口类型 标志值 描述
    CONSTANT_Utf8 1 UTF-8 编码的Unicode字符串
    CONSTANT_Integer 3 int类型字面值
    CONSTANT_Float 4 float 类型字面值
    CONSTANT_Long 5 long类型字面值
    CONSTANT_Double 6 double 类型字面值
    CONSTANT_Class 7 对一个类或接口的符号引用
    CONSTANT_String 8 string 类型字面值
    CONSTANT_Fieldref 9 对一个字段的符号引用
    CONSTANT_Methodref 10 对一个类中声明的方法的符号引用
    CONSTANT_InterfaceMethodref 11 对一个接口中声明的方法的符号引用
    CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用
    CONSTANT_MethodHandle 15 方法句柄
    CONSTANT_MethodType 16 方法类型
    CONSTANT_InvokeDynamic 18 动态调用
  4. access_flags
    紧接常量池后面的两个字节称为 access_flags ,access_flags项的值是一个标记的掩码,用于表示该类或接口的访问权限和属性。下表规定了每个标志设置后的解释。

    标志名 设置后的含义 设置名
    ACC_PUBLIC 0x0001 public 类型 类和接口
    ACC_FINAL 0x0010 类为final类型 只有类
    ACC_SUPER 0x0020 使用新型的invokespecial语义 类和接口
    ACC_INTERFACE 0x0200 接口类型,不是类 类型 所有的接口,没有类
    ACC_ABSTRACT 0x0400 abstract类型 所有的接口,部分类
  5. this_class
    接下来的两个字节为this_class项,它是一个队常量池的索引。this_class项的值必须是constant_pool表的有效索引。索引处的constant_pool条目必须是CONSTANT_Class_info结构,它表示这个类文件定义的类或接口。

  6. super_class
    在class文件中,紧接在this_class 之后的是 super_class 项,它是一个两个字节的常量池索引。对于一个类,super_class项的值必须为零或者必须是constant_pool表的有效索引。
    如果super_class项的值为非零,则该索引处的constant_pool项必须是CONSTANT_Class_info结构,它表示这个类文件定义的类的直接超类。无论是直接超类还是它的任何超类都不能在它的类文件结构的access_flags项中设置ACC_FINAL标志。
    如果super_class项的值为0,那么这个类文件必须表示class对象,这是唯一没有直接超类的类或接口。
    对于接口,super_class项的值必须始终是constant_pool表的有效索引。索引处的constant_pool条目必须是表示类对象的CONSTANT_Class_info结构。

  7. interfaces_count 和 intefaces
    紧接着 super_class 的是 interfaces_count。此项的含义为:在文件中该类直接实现或者由接口所扩展的父接口的数量。在这个计数的后面,是名为 interfaces 的数组,它包含了对每个由该类或者接口直接实现的父接口的常量池索引。

  8. fields_count 和 fields
    在class文件中,紧接在 interfaces 后面的是对在该类或者接口中所声明的字段的描述。首先是名为 fields_count 的计数,它是类变量和实例变量的字段的数量总和。在这个计数后面的是不同长度的 field_info 表的序列。只有在文件中由类或者接口声明了的字段才能在 fields 列表中列出。在 fields 列表中,不列出从超类或者父接口继承而来的字段。另一方面,fields 列表可能会包含在对应的java源文件中没有叙述的字段,这是因为java编译器可能会在编译时向类或者接口添加字段,添加进去的字段使用 Synthetic 属性标识。fields_descriptor 标识对应如所示:

    基本类型 含义
    B byte
    C char
    D double
    F float
    I int
    J long
    S short
    Z boolean
    V void
    L Object
    [ array(例如:[B ,表示 byte[] [Ljava/lang/String 表示 string[] ,多维数组 [[C [[[Ljava/lang/String)
  9. methods_count 和 methods
    在class文件中紧接着fields 后面的是对该类或者接口中所声明的方法的描述。首先是名为 methods_count 的计数,它是一个双字节长度的对于该类或者接口中声明的所有方法的总计数。这个总计数只包含在该类或者接口中显式定义的方法(从超类或者父接口中集成来的方法不被计入)。
    方法表中的每个值都必须是method_info结构,该结构给出了这个类或接口中方法的完整描述。如果在method_info结构的access_flags项中都没有设置ACC_NATIVE和ACC_ABSTRACT标志,那么还会提供实现该方法的Java虚拟机指令。

method_info结构表示由这个类或接口类型声明的所有方法,包括实例方法、类方法、实例初始化方法和任何类或接口初始化方法。方法表不包括表示从超类或超接口继承的方法的项。
如下所示:


image.png

图中字节码部分其实就是java 的汇编语言,在 jvms 8 的第六、七章有说明,jvms 的下载地址为 https://docs.oracle.com/javase/specs/index.html,值得注意的是一定要注意版本。

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

推荐阅读更多精彩内容