手把手教你撸一个Mini JVM系列(2)之解析Class File -- 常量池

引子:

前面已经解析了一个class文件的魔数和class文件的版本号, 这篇文章重点要解析的就是class文件中的一个重要的部分——常量池.
class文件中的所有字面常量(包括类名, 方法名,字段名, 字段类型等等都是放在常量池中的)这样做的目的是因为class文件的其他部分可能都要使用到这些内容, 如果每个地方用到都保存一份那么太浪费空间, 所以把这些数据都放到常量池中, 其他地方要引用就直接引用常量池就可以了. 所以常量池是class文件中很重要的一部分.

1. 常量池结构

首先直观的看一个常量池到底长什么样(其实在class文件都是一堆的字节, 只不过每个字节在特定的上下文都代表指定的意思)

图1-1 CONSTANT-POOL

可以看到class文件的版本号后紧跟的就是常量池. 常量池的头两个字节表明了常量池中常量项的个数, 因为只有两个字节所以常量项是有数量限制的. 具体多少个可以自行计算. 常量项个数后面紧跟的就是各个常量项了. 每个常量项都有一个1个字节的tag标志位, 用于表示这个常量项具体代表的内容, 从图中可以看到如果tag是07的话就表示这是一个Class Info的常量项, 从名字就可以看出来这是一个表示Class信息的常量项.
用专业一点的术语描述的话常量池中保存的内容就是字面量和符号引用. 字面量就像类似于文本字符串, 声明为final的常量值. 符号引用包括3类常量类和接口的全限定名, 字段名称和描述符, 方法名称和描述符.
特别要注意的一点是常量池中的常量项的索引是从1开始的, 这样做的目的是满足后面其他结构中需要表明不引用任何一个常量项的含义, 这个时候就将索引值置为0.

2. 常量项的表示

从前面的描述可以总结出来, 所有的常量池项都具有如下通用格式:

cp_info {
   u1 tag;
   u1 info[]; 
}

常量池中,每个cp_info项(也就是常量项)的格式必须相同,它们都以一个表示cp_info类型的单字节"tag"项开头. 后面info[]项的内容由tag的类型所决定.

tag的类型有如下几种


图1-2 TAG

3. 常用的常量项

  1. Class Info

        CONSTANT_Class_Info {
            u1 tag;
            u2 name_index;
        }
    
    • tag的值为7
    • name_index指向了常量池中索引为name_index的常量项
  2. UTF8 Info

        CONSTANT_UTF8_Info {
            u1 tag;
            u2 length;
            u1 bytes[length];
        }
    
    • tag的值为1
    • length表示这个UTF8编码的字符串的字节数
    • bytes[length]表示length长度的具体的字符串数据

    注意: 因为class文件中的方法名, 字段名等都是要引用UTF8 Info的, 但是UTF8 Info的数据长度就是2个字节, 所以方法名, 字段名的长度最大就是65535.

  3. String Info

        CONSTANT_String_INFO {
            u1 tag;
            u2 string_index;
        }
    
    • tag的值为8
    • string_index指向了常量池中索引为string_index的常量项
  4. Field_Ref Info

        CONSTANT_Fieldref_Info {
            u1 tag;
            u2 class_index;
            u2 name_and_type_index;
        }
    
    • tag的值为9
    • class_index指向了常量池中索引为class_index的常量项, 且这个常量项必须为Class Info类型
    • name_and_type_index指向了常量池中索引为name_and_type_index的常量项, 且这个常量项必须为Name And Type Info类型
  5. Method_Ref Info

        CONSTANT_Methodref_Info {
            u1 tag;
            u2 class_index;
            u2 name_and_type_index;
        }
    
    • tag的值为10
    • class_index指向了常量池中索引为class_index的常量项, 且这个常量项必须为Class Info类型
    • name_and_type_index指向了常量池中索引为name_and_type_index的常量项, 且这个常量项必须为Name And Type Info类型
  6. NameAndType Info

        CONSTANT_NameAndType_Info {
            u1 tag;
            u2 name_index;
            u2 descriptor_index;
        }
    
    • tag的值为12
    • name_index指向了常量池中索引为name_index的常量项
    • descriptor_index指向了常量池中索引为descriptor_index的常量项

以上这些就是常用的常量项, 或者说在我的mini jvm中常用的常量项, 至于其他的常量项也是类似, 可以参考oracle关于常量项的定义自行分析

3. 具体实现

因为我使用的java实现jvm, 所以以上的常量项其实就相当于是一个个的类, 解析的过程就是初始化一个一个的类. 具体的代码实现就不在这里讲述了, 请参考代码中的com.aaront.exercise.jvm.constant这个包下的内容和ClassParser这个类的实现

4. 访问标志、类和接口

这三个内容是紧跟在常量池之后的, 而且比较简单, 所以在这里简单介绍一下

  1. 访问标志

访问标志实际上就是当前class的修饰符, 看一下访问标志的定义就知道了

图1-3 ACCESS-FLAG

访问标志由2个字节表示, 这个class有哪个修饰符对应的位就置为1, 非常的简单

紧接在访问标志后面的是this class和super class, 这两个的值都是指向常量池的中某一个常量项同时所指向的常量项必须是Class Info类型

  1. 接口

紧接在类后面的是接口, 因为一个class可以实现多个接口, 所以和类不同的是接口需要有一个字段来标明这个类实现了多少个接口, 所以开头的两个字节是表明class实现的接口数量, class实现了几个接口后面就有几个接口数量, 这和class一样都是指向常量池中的某个常量项同时常量项的类型必须是Class Info类型.

4. 总结

常量的解析到此就结束了, 常量池是一个非常重要的结构, 整个class文件的各个部分包括后面要提到的字段, 方法, 属性中都有对常量池的引用, 也正是因为有了常量池class文件才可以节省一大部分的空间.

5. 代码地址

6. 本系列其他文章

手把手教你撸一个Mini JVM系列(1)之解析Class File -- 初探
手把手教你撸一个Mini JVM系列(3)之解析Class File -- 字段、方法、属性
手把手教你撸一个Mini JVM系列(4)之执行引擎
手把手教你撸一个Mini JVM系列(5)之源码分析 -- 常量池、访问标志、类索引
手把手教你撸一个Mini JVM系列(6)之控制流 -- 条件判断和循环

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

推荐阅读更多精彩内容