JAVA虚拟机入门(1)---------类文件结构 (下)

原文链接:http://blog.csdn.net/hollow12384/article/details/52189590
转载请注明出处

大家好,这篇博客是继JAVA虚拟机入门(1)—–类文件结构(上)的,没看过那篇博客的最好先看那篇博客~(链接:http://blog.csdn.net/hollow12384/article/details/52183804
由于始终围绕上篇博客的例子进行讲解,这次还是先把图放出来,这图和上篇博客的一模一样,只是为了大家方便观看。

这里写图片描述

(五)类索引、父类索引,接口类索引集合(至少4个字节)
承接在访问标志后的就是类索引、父类索引,接口类索引集合。类索引用于确定这个类的全限定名,有2个字节;父类索引用于确定这个类的父类的全限定名,有2个字节,且除了Object类外,其余类这个索引不可能为空(都默认继承Object);接口类索引集合跟之前的常量池接口差不多,前两个字节表示一共有多少个接口,如果是00 00说明没有implement 接口。
还是针对上篇博客中的例子,跟在0021后面的就是 00 01,说明这个类的全限定名要去第一个常量找,找到常量池中的第一个常量,为07 00 02,上次我们解析过了,07代表的是CONSTANT_Class_info,是一个指向类的索引,这里0002指向的是第二个常量,由于之前已经解析过了,这里就不再赘述,第二个常量解析出来的结果正是javaLearning/test,也就是这个类的全限定名。
紧跟着00 01的是00 03,说明父类权限定名要去第三个常量找,步骤和上面的一模一样,解析出来的结果是Java/lang/Object,没错吧!没有继承其他类的类默认继承Object。接下来就是00 03后面的00 00,我们说过,00 00代表的是没有接口,在我们这个例子中确实没有继承接口,bingo。

(六)字段表
回顾一下,到目前为止,我们已经解析了魔数,版本号,常量池,访问标志和类索引、父类索引和接口索引集合,接下来将正式进入类里面探索每一个字段在字节码文件中怎么表示的。在索引集合后跟着的就是字段表了。什么是字段呢?举个例子吧,private int k = 0,这里的k就可以理解为是字段。当然,字段实际上是包括它的属性的,比如private和int等。首先我们先看一下字段表的结构,这会指引我们对字节码进行解析:

这里写图片描述

要注意表中的数据是针对于一个field(字段)的,但是我们知道,在一个类中,往往有许多字段,比如private int a; private int b; 这样的话就需要一个计数器来表示一共有多少个字段了,因此字段表一开始的2个字节就是用于表示一共有多少个字段的。在我们的例子中是00 01,也就是说只有一个字段,这是当然。因为我们就只有一个字段:private int a = 1;
接下来,我们将结合实例对里面每一个字段进行解释。

(1)access_flags(2个字节)
还记得(四)中的访问标志吗,这里的access_flags和那个差不多。下面是access_flags可以设置的一些属性。

这里写图片描述

不过注意里面的这些属性,有些是可以在一起设置的,有些是相斥的,具体哪些相斥可以参考java制定规则,这里由于将焦点放在解析字节码文件,因此不多赘述。在我们的例子中,access_flags是在00 01后的00 02,根据上面的属性表可以得知对应的是ACC_PRIVATE,正确。

(2)name_index(2个字节)
name_index表示的是字段的简单名称的索引,何谓简单名称呢?这是相对于全限定名而言的,在(五)中我们已经知道,全限定名就是类似于javaLearning/test�这种结构的(包/类),而简单名称则就是一个名字而已,比如private int a = 1(还是这个例子),简单名称就是a。知道这个概念后,看回例子,name_index为00 05,去常量池的第5个常量找,对应的位置是Offset为00000030那一行的01 0001 61,这个就是第五个常量了,01表示是CONSTANT_Utf8_Info,0001说明长度为1个字节,61表示的是‘a’,怎样?是不是我们例子中的那个字段a!再一次成功解出。

(3)descriptor_index(2个字节)
我们已经解析出来private和a,但是还有一个关键的a的类型还没解析出来,那应该怎么得到a的类型int呢?这就需要描述符了。描述符是一个相对于前面两个复杂一点的东西。它主要是用于描述字段的数据类型、方法的参数列表(包括数量、类型和顺序)和返回值。首先我们先讲解描述符的描述规则,一旦理解这个,解析也就so easy了。根据描述符的描述规则,基本数据类型(int,byte,char,double,float,long,short,boolean)以及代表无返回值的void都用一个大写字符表示,而对象类型就用L + 对象全限定名表示,而数组类型每一个维度都用一个前置的”[“表示。举个例子:String[][][]表示为[[[Ljava.lang.String,int[]表示为[I具体如下表:

这里写图片描述

大家也注意到了,在说描述符时,我并没有局限于描述字段,而是提到了方法,没错,描述符也用于描述方法。用描述符描述方法时,按照先参数列表再返回值的顺序描述。参数列表按照参数的严格顺序放置在()中。继续举个例子:int getIntTest()用描述符描述就是()I,void k(int a,String[]k,int b)用描述符描述就是(I[Ljava.lang.StringI)V。相信大家对描述符怎么得来的应该已经有了一定理解,接下来就是实战了。再次献上那个远古的例子(参照本博客刚开头那张表),在实例中descriptor_index对应的字节码是00 06,去常量池中第六个常量中找,位置是offset为00000030的01 00 01 49,对应的值为I,也就回答了我们在前面提到的问题了,这个I就是int。在descriptor_index后跟着的是attrubute_count,但是因为在这里是00 00,说明没有其他属性了。不过如果是final static int a = 9;那么属性表集合将会有一个指向常量池中9的属性。

(七)方法表集合
在字段表后面就是方法表集合了,由于方法表集合和字段表集合十分类似,因此直接给出方法表结构以及方法表访问结构方法表结构如下:
[图片上传中。。。(5)]
方法访问标志如下:

这里写图片描述

接着就直接对实例中的方法表进行解析了(毕竟真的和字段表很像):
看到Offset为000000E0中的00 02,说明方法表一共有两个方法。咦?我们不是只写了一个方法吗?怎么这里说是两个?其实,要注意到,每个类都会有属于自己的构造函数,如果自己没有写构造函数的话,那么编译器会帮我们添加一个实例构造器,因此这多出来的一个方法就是构造方法了。
接下来看第一个方法,00 01说明是ACC_PUBLIC,00 07找到常量池的第七个常量,位于Offset为00000030的01 00 06 3C 69 6E 69 74 3E,翻译出来就是,再看00 08指向常量池的第8个常量,读出来为()V,说明是返回值为0,参数为空的函数;接下来的00 01说明属性表只有一个属性,是00 09,读取第9个常量,读出来是Code,说明这个属性是方法的字节码描述。总结一下就是我们读出来一个public的无参构造函数,而关于方法的字节码描述在后面的属性表中会进行解释。
第二个方法是00 01 —-> public,00 09,找到第九个常量,0A 00 03 00 0B,关于常量池中的tag在上篇博客有给出一张表,根据里面的规则进行转化,最后的结果是getIntTest,就是方法的名字了。
注意:
(1)一个类如果没有override一个父类的方法,那么父类的方法不会出 现在这个类的常量池中
(2)在java中重载一个方法,其实除了一个和原方法一模一样的名称外,还需要一个与原方法不同的特征签名。什么是特征签名呢?特征签名是一个方法中各个参数在常量池中的字段引用的集合,而返回值是不属于方法中参数的,因此无法通过返回值来对一个原有的方法进行重载。
(3)在Class文件格式中,特征签名的范围更大一些,只要不是完全一样的描述符就可以了,因此只有返回值不同也是可以算作重载的。因此同一个类中如果两个类只有返回值不同时可以的,因为这个类被编译成.class字节码文件后的描述符是不一样的

七:总结
原本在方法表后就是属性表了,但是还记得我在类文件结构(上)一开篇提到的吗?我是为了学习热修补而开始学习java虚拟机的,因此关于属性表和后面的知识,解析起来方法上是一样的,为了让我的目标更明确,我决定类文件结构就到此为止。
当然,如果有比较多的朋友还想我写属性表和后面的内容,我会找个时间写一遍的。
下一篇博客就是类加载机制了,这一块是直接和热修补技术相关的,因此希望大家继续耐心地支持我,谢谢。

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

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,820评论 6 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,524评论 18 399
  • 代理 代理设计模式的作用:1.A对象监听B对象的一些行为,A成为B的代理2.B对象想告诉A对象一些事情,A成为B的...
    挖掘机阅读 237评论 0 0
  • 跟他硬着说话吧,真心是没有什么价值,但是你顺着他说话吧,气立马就消,你身边有这样的他嘛?是不是瞬间感觉事半功倍的节...
    星在远程阅读 228评论 0 0
  • 放手磨练,爱的至高境界 ——茹心 这些日子,因为总在厂房与山卡拉的宿舍两边奔走,加之交通不便,公司便安排泉叔专车接...
    茹心阅读 348评论 0 1