本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍。 本文将会继续介绍class文件中未讲解的信息。 先回顾一下上面一篇文章。 在上一篇博客中, 我们介绍了:

this_class 对当前类的描述
super_class 对当前类的超类的描述
interfaces_count 当前类直接实现的接口的数量或当前接口直接继承的接口的数量
interfaces 对当前类或当前接口直接实现或继承的所有接口的描述

下面继续介绍class文件中的其他信息。

class文件中的fields_count和fields

fields_count描述的是当前的类中定义的字段的个数, 注意, 这里包括静态字段, 但不包括从父类继承的字段。 如果当前class文件是由一个接口生成的, 那么这里的fields_count描述的是接口中定义的字段, 我们知道, 接口中定义的字段默认都是静态的。此外要说明的是, 编译器可能会自动生成字段, 也就是说, class文件中的字段的数量可能多于源文件中定义的字段的数量。 举例来说, 编译器会为内部类增加一个字段, 这个字段是指向外围类的对象的引用。

位于fields_count下面的数据叫做fields, 可以把它看做一个数组, 数组中的每一项是一个field_info 。这个数组中一共有fields_count个field_info , 每个field_info都是对一个字段的描述。 下面我们详细讲解field_info的结构。 每个field_info的结构如下:


(1)access_flags

其中access_flags占两个字节, 描述的是字段的访问标志信息。 这里就不在详细介绍了, 下面给出一张表格(该表格来自《深入Java虚拟机》):

(2)name_index

access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前字段的字段名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前字段的字段名。

(3)descriptor_index
name_index下面的两个字节叫做descriptor_index , 它同样是一个指向常量池的索引, 它描述的是当前字段的描述符。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前字段的描述符(关于字段描述符, 在前面的博客中已经有过详细的讲解, 如果不明白, 请参考前面的博客:深入理解JVM Class文件格式(二))。

(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 这是对当前字段所具有的属性的描述。 这里的属性和源文件中的属性不是同一个概念, 在源文件测层面中, 属性是字段的另一种叫法, 希望读者不要疑惑。读者也不要轻视class文件中的属性, 这些属性可以描述很多的信息。 我们会在后面的文章中进行介绍。

attributes_count表示这个字段有几个属性。attributes 可以看成一个数组, 数组中的每一项都是一个attribute_info , 每个attribute_info 表示一个属性, 数组中一共有attributes_count个属性。可以出现在filed_info中的属性有三种, 分别是ConstantValue, Deprecated, 和 Synthetic。 这些属性会在后面的文章中进行介绍。

下面我们以代码的形式进行解释, 源码如下:

package com.jg.zhang;public class Programer extends Person{private Computer computer;public Programer(Computer computer){this.computer = computer;}public void doWork(){computer.calculate();}
}

反编译之后, 常量池中会有如下信息(这里省略了大部分无关信息):

Constant pool:.........
.........#5 = Utf8               computer#6 = Utf8               Lcom/jg/zhang/Computer;.........
.........{private com.jg.zhang.Computer computer;flags: ACC_PRIVATE.........
.........}

从反编译的结果可以看出, 源文件中定义了一个Computer类型的字段computer, 并且是private的。 然后常量池中有这个字段的字段名和描述符。 其中常量池第五项的CONSTANT_Utf8_info是字段名, 第六项的CONSTANT_Utf8_info是该字段的描述符。这里有一点需要说明, 在反编译Programer.class时,由于computer是私有的, 要加- private选项, 否则的话, 虽然常量池中有字段引用信息, 但是不会输出字段信息, 即下面这两行不会输出:
private com.jg.zhang.Computer computer;
flags: ACC_PRIVATE

如果在javap中加入 - private选项, 那么就会有上面两行的输出。 使用的命令如下:

  javap -c -v -private -classpath . com.jg.zhang.Programer

根据反编译的结果,可以下面给出示意图, 该图说明了与computer相对应的field_info是如何引用常量池的 ( 其中虚线范围内表示常量池):

class文件中的methods_count和methods

fields下面的信息是methods_count和methods 。 methods_count描述的是当前的类中定义的方法的个数, 注意, 这里包括静态方法, 但不包括从父类继承的方法。 如果当前class文件是由一个接口生成的, 那么这里的methods_count描述的是接口中定义的抽象方法的数量, 我们知道, 接口中定义的方法默认都是公有的。此外需要说明的是, 编译器可能会在编译时向class文件增加额外的方法, 也就是说, class文件中的方法的数量可能多于源文件中由用户定义的方法。 举例来说: 如果当前类没有定义构造方法, 那么编译器会增加一个无参数的构造函数; 如果当前类或接口中定义了静态变量, 并且使用初始化表达式为其赋值, 或者定义了static静态代码块, 那么编译器在编译的时候会默认增加一个静态初始化方法 。

位于methods_count下面的数据叫做methods , 可以把它看做一个数组, 数组中的每一项是一个method_info 。这个数组中一共有methods_count个method_info , 每个method_info 都是对一个方法的描述。 下面我们详细讲解method_info 的结构。 每个method_info 的结构如下, 几乎和field_info的结构是一样的:

(1)access_flags
其中access_flags占两个字节, 描述的是方法的访问标志信息。 这里就不在详细介绍了, 下面给出一张表格(该表格来自《深入Java虚拟机》):

(2)name_index

access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前方法的方法名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前方法的方法名。

(3)descriptor_index

name_index下面的两个字节叫做descriptor_index , 它同样是一个指向常量池的索引, 它描述的是当前方法的描述符。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前方法的描述符(关于方法描述符, 在前面的博客中已经有过详细的讲解, 如果不明白, 请参考前面的博客: 深入理解JVM Class文件格式(二))。

(4)attributes_count和attributes

descriptor_index 下面是attributes_count和attributes 。 这是对当前方法所具有的属性的描述。 这里的属性和源文件中的属性不是同一个概念, 在源文件测层面中, 属性是字段的另一种叫法, 希望读者不要疑惑。读者也不要轻视class文件中的属性, 这些属性可以描述很多的信息。 我们会在后面的文章中进行介绍。

attributes_count表示这个字段有几个属性。attributes 可以看成一个数组, 数组中的每一项都是一个attribute_info , 每个attribute_info 表示一个属性, 数组中一共有attributes_count个属性。可以出现在method_info 中的属性有四种, 分别是Code, Deprecated, Exceptions 和Synthetic。 在这几个属性中, 尤其是Code和Exceptions 非常重要, 这两个属性对于在class文件中完整描述一个方法起着至关重要的作用, 其中Code属性中存放方法的字节面指令,Exceptions 属性是对方法声明中抛出的异常的描述 。 这两属性以及其他一些属性, 会在下一篇文章中详细介绍, 敬请关注。

介绍完了每个method_info的结构, 下面我们以代码来说明, 还是使用上面的源码:

package com.jg.zhang;public class Programer extends Person{private Computer computer;public Programer(Computer computer){this.computer = computer;}public void doWork(){computer.calculate();}
}

反编译之后, 常量池中会有如下信息(这里省略了大部分无关信息):

Constant pool:.........#7 = Utf8               <init>#8 = Utf8               (Lcom/jg/zhang/Computer;)V.........#12 = Utf8               ()V.........#19 = Utf8               doWork{.........public com.jg.zhang.Programer(com.jg.zhang.Computer);flags: ACC_PUBLIC.........public void doWork();flags: ACC_PUBLIC.........
}

由反编译结果可以看出, 该类中定义了两个方法, 其中一个是构造方法, 一个是doWork方法, 且这两个方法都是public的。 这两个方法的描述信息都存放在常量池。 其中第7项的CONSTANT_Utf8_info为构造方法的方法名, 第8项的CONSTANT_Utf8_info为构造方法的方法描述符, 第19项的CONSTANT_Utf8_info为doWork方法的方法名, 第12项的CONSTANT_Utf8_info为doWork方法的方法描述符。

根据常量池中的信息, 可以得出如下的示意图, 该示意图形象的说明了class文件中的method_info是如何引用常量池中的数据项来描述当前类中定义的方法的。 图中虚线范围内表示常量池所在的区域:

总结

到此为止, 我们就介绍完了class文件中的fields和methods, 进行一下总结。

fields是对当前类中定义的字段的描述, 其中每个字段使用一个field_info表示, fields中有fields_count个field_info。

methods是对当前类或者接口中声明的方法的描述, 其中每个方法使用一个method_info表示, methods中有methods_count个method_info。

在下一篇博客中, 将会介绍class文件中的各个属性, 敬请关注。

https://my.oschina.net/u/3892023/blog/2961140

深入理解 JVM Class文件格式(七)相关推荐

  1. 深入理解 JVM Class文件格式(九)

    经过前八篇关于class文件的博客, 关于class文件格式的内容也基本上讲完了. 本文是关于class文件格式的最后一篇. 在这篇博客中, 将会讲解关于方法的几个属性. 理解这篇博客的内容, 对于理 ...

  2. 深入理解 JVM Class文件格式(八)

    在本专栏的第一篇文章 深入理解Java虚拟机到底是什么 中, 我们主要讲解了什么是虚拟机, 这篇博客是对JVM的一个概述. 在随后的几篇文章中,一直在讲解class文件格式. 在今天这篇博客中, 将会 ...

  3. 深入理解 JVM Class文件格式(五)

    (8) CONSTANT_Class_info 常量池中的一个CONSTANT_Class_info, 可以看做是CONSTANT_Class数据类型的一个实例. 他是对类或者接口的符号引用. 它描述 ...

  4. 深入理解 JVM Class文件格式(三)

    ** JVM常量池中各数据项类型详解 ** 关于常量池的大概内容, 已经在 深入理解 JVM Class文件格式(一) 中讲解过了, 这篇文章中还介绍了常量池中的11种数据类型. 本文的任务是详细讲解 ...

  5. 深入理解 JVM Class文件格式(十)

    到此, 所有关于class文件格式的重要内容都已经讲解完了, 不敢说面面俱到, 但是敢说大部分重要的内容都包含在内了.前前后后用了9篇博客来专门讲解class文件结构, 为什么花那么多的时间和精力来介 ...

  6. 深入理解 JVM Class文件格式(六)

    经过前几篇文章, 终于将常量池介绍完了, 之所以花这么大的功夫介绍常量池, 是因为对于理解class文件格式,常量池是必须要了解的, 因为class文件中其他地方,大量引用了常量池中的数据项. 对于还 ...

  7. 深入理解JVM类文件格式

    我们知道Java最有名的宣传口号就是:"一次编写,到处运行(Write Once,Run Anywhere)",而其平台无关性则是依赖于JVM, 所有的java文件都被编译成字节码 ...

  8. 深入理解 JVM Class文件格式(二)

    ** class文件中的特殊字符串 ** 特殊字符串是常量池中符号引用的一部分,包括三种: 类的全限定名, 字段和方法的描述符, 特殊方法的方法名. 下面我们就分别介绍这三种特殊字符串. (1) 类的 ...

  9. 深入理解 JVM Class文件格式(一)

    ** 一.JVM体系结构 ** ** 二.class格式文件概述 ** class文件是一种8位字节的二进制流文件, 各个数据项按顺序紧密的从前向后排列, 相邻的项之间没有间隙, 这样可以使得clas ...

最新文章

  1. c4d教程-太空火车站场景创作视频教程Skillshare – Create A Space Train Scene With Cinema 4D Redshift Render
  2. 在windows XP运行3660路由器仿真器
  3. placeholder在不同浏览器下的表现及兼容方法
  4. 20140710文安c++面试总结
  5. JZOJ 5377. 【NOIP2017提高A组模拟9.19】开拓
  6. c语言 结构体_颖儿教你学C语言结构体,全面讲解,让程序小白玩转结构体编程...
  7. SAP License:SAP Business One 与SAP R/3的区别
  8. LeetCode-三数之和
  9. Windows无法安装到这个磁盘,选中的磁盘具有MBR分区表的解决方法
  10. win10相机计算机无法使用,Win10相机打不开 报错“0xa00f4244”要怎么解决?
  11. 解析经纬度,将度分转成度
  12. spark报错:Cannot overwrite a path that is also being read from.
  13. Interactive Speech and Noise Modeling for Speech Enhancement
  14. php ua解析,UA识别有什么用?
  15. 深入浅出内存马(一)
  16. 高分口碑神作《诡秘之主》《剑来》是第四届橙瓜网络文学奖大热门
  17. 输入汉字获得拼音(VB.net)
  18. HIS接口--LIS 与 HIS 跳转URL
  19. 十个好用的iOS开发辅助工具与资源
  20. 慢跑在一座陌生的城市

热门文章

  1. mysql为什么添加索引_当我添加新索引时,为什么MySQL中索引的基数保持不变?
  2. eltree ref什么时候有_Vue3响应式系统源码解析-Ref篇
  3. 计算机整个文稿应用回顾主题,《计算机应用基础》精品课程电子教案-PowerPoint 2003...
  4. 爱因斯坦为什么不是普通人?看他怎么喝茶就明白了,差距太明显了!没法比.......
  5. 男生的哪个“不要”是真的不要?
  6. 拉屎能赚钱?在马桶上月入过万?原来卫生间里还有这么多隐藏福利,超模君都惊了……
  7. “Python简直万能!”拜托快醒醒!
  8. 快速成长为数据挖掘高手的秘诀
  9. android 只能输入汉字,EditText限制输入的几种方式及只显示中文汉字的做法
  10. vscode函数跳转插件_人生苦短,我们为 Cocos Creator 开发的插件和工具