基础概念

  • 任何一个 Class 文件都对应着唯一的一个类或接口的信息
  • Class 文件是一组以字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符。这使得整个 Class 文件中存储的内容几乎全部是 程序运行的必要数据
  • Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构只有“无符号数” 和 “”两种数据类型

无符号数

无符号数属于基本的数据类型,以 u1,u2,u4,u8 来分别代表 1 个字节、2 个字节、4 个字节、8 个字节

表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表的命名都习惯性地以“_info” 结尾

对上面代码进行编译得到 .class 文件

组成部分

一、魔数


每个Class文件的头4 个字节被称为魔数,它的唯一作用是确定这个文件是否是一个能被虚拟机接受的 Class 文件

二、版本号


紧接着魔数的 4 个字节存储的是 Class 文件的版本号

  • 第5个和第6个字节是次版本号:次版本号未使用,全部固定为 0
  • 第7个和第8个字节是主版本号:Java的版本号是从 45 开始的,JDK1.1之后每个JDK 大版本的发布,主版本号向上加 1,0x003B 对应的十进制为 59(我使用的JDK 15, 所以是主版本号是59)

三、常量池

  • 紧接着主次版本之后的是常量池入口,常量池可以比喻为 Class 文件里的资源仓库,它是 Class 文件结构中与其它项目关联最多的数据。通常也是占用 Class 文件空间最大的数据项目之一
  • 常量池的入口需要放置一项 u2 类型的数据,表示常量池容量计数值,这个容量计数是从 1 开始,而不是从 0 开始


0x0016 转化为10进制为22, 表示常量池中有 21 个常量,索引值的范围为 1~22

  • 常量池中主要存放两大类变量:字面量符号引用

  • 常量池中每一个常量都是一张表,截至 JDK13,常量表中一共有 17 种不同类型的常量

例子分析:第一项常量


第一项常量的标志位为 0x0A, 对应十进制 10,则表示这个常量属于 CONSTANT_Methodref_info 类型,此类型常量代表类中方法的符号引用,CONSTANT_Methodref_info 的结构如下图所示:一共占5个字节

tag 是标志位,用于区分常量类型, index 是索引值,图中可以参数 第二个index 为 0x02 ,指向常量池中的第二项常量,继续查找第二项常量:为 0x03 ,查表可知这是一个 CONSTANT_Class_info 类型的常量,表示类或者接口的符号引用

例子分析:第二项常量



到此为止,分析了TestClass.Test 常量池中 21 个常量的两个还未提到的 19 个常量都可以用类似的方法分析出来,可以利用一个专门用于分析字节码的工具:javap

常量池中的17 种数据类型的结构总表


四、访问标志

在常量池结束之后,紧接着的 2 个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息。包括:这个Class 是类还是接口、是否定义为 public 类型、是否定义为 abstract 类型、如果是类的话,是否被声明为 final、等等。
access_flags 中一共有 16 个标志位可以使用,当前只定义了 9 个。

示例的 TestClass 文件是一个普通的 Java 类文件,不是接口、枚举、注解或者模块、被public 关键字修饰但没有被声明为 final 和 abstract。
ACC_PUBLIC 和 ACC_SUPER 标志为真,因此它的 access_flags 的值应为:0x0001 | 0x0020 = 0x0021

五、类索引、父类索引与接口索引集合

Class文件由这三项来确定类的继承关系

  • 类索引用于确定这个类的全限定名
  • 父类索引用于确定这个类的父类的全限定名
    Java 语言不允许多继承,所以父类索引只有一个,除了 java.lang.Object 之外,所有的 Java 类都有父类,因此除了 java.lang.Object 之外,所有的 Java 类的父类索引都不为0
  • 接口索引集合用来描述这个类实现了哪些接口


从图中可以看出,类索引、父类索引、接口索引分别为0x0008,0x0002,0x0000,即类索引为8,父类索引为2,接口索引集合大小为0。再看常量池的内容正好对上了。

对于接口索引集合,入口的第一项 u2 类型的数据为 接口计数器,表示索引表的容量。如果该类没有实现任何接口,则该计数器为0,后面接口的索引表不再占有任何字节。

六、字段表集合

字段表用于描述接口或者类中声明的变量


字段修饰符 放在 access_flags 中,是一个u2 的数据类型,其中可以设置标志位,可以设置的字段访问标志如下图:

跟着 access_flags 的是两项索引值:name_index 和 descriptor_index ,都是对常量池的引用,分别代表着字段的简单名称和以及字段和方法的描述符
描述符的作用是用来描述字段的数据类型方法的参数列表(包括数量、类型和顺序)和返回值

对于 TestClass 文件
如下图第一个 u2 类型的数据为容量计数器 fields_count,值为 0x0001,表示这个类只有一个字段表数据

如下图

紧跟着容量计数器的是 access_flag 标志,值为 0x0002,代表 private 修饰符的 ACC_PRIVATE 标志位为真,其他修饰符为假

代表字段名称的 name_index 的值为0x000B,即 11,从常量池中可以得出第 11 项常量是一个 CONSTANT_Utf8_info 类型的字符串,值为 m,
代表字段描述符的 descroptor_name 的值为 0x000C ,即12,从常量池中得出第 12 个常量是 I ,根据描述符表,可以得到是基本类型 int
根据这些信息,我们可以推断出原代码定义的字段为 “private int m”!!!

七、方法表集合

Class 文件存储格式中对方法的描述和对字段的描述采用了几乎完全一致的方式,方法表的字段如同字段表一样。

八、属性表集合

Class文件、字段表、方法表 都可以携带自己的属性表集合

详细内容看周志明《深入理解 Java 虚拟机》

参考链接:

  • 《深入理解 Java 虚拟机》
  • https://louluan.blog.csdn.net/article/details/39960815
  • https://blog.csdn.net/qq_36714200/article/details/108908510

Java Class类文件的结构相关推荐

  1. java怎编写么解析一个类型_DAY3:你必须知道的java虚拟机之类篇——类文件的结构...

    马上过年啦,不知道大家今年有没有投资基金股票呢?是赚的盆满钵满还是拍断大腿,可以评论区一起交流交流,秀一秀哈哈,反正我是没来得及上车. 暴富西不可能暴富的啦,打工人嘛几能写写文章啦-记得点赞➕关注呀 ...

  2. 【java】详解Java的类文件(class文件)结构

    1.概述 转载:详解Java的类文件(class文件)结构 大家好,我是二哥呀,今天我拿了一把小刀,准备解剖一下 Java 的 class 文件. CS 的世界里流行着这么一句话,"计算机科 ...

  3. Class类文件的结构

    2019独角兽企业重金招聘Python工程师标准>>> Class类文件的结构 Class类文件的结构 任何一个Class文件都对应着唯一一个类或接口的定义信息,但反之类和接口并不一 ...

  4. 详解Class类文件的结构(上)

    前言 相信搞Java开发的同学都经常会接触到Class类文件,了解了JVM虚拟机之后也会大量接触到class字节码,那么它到底是什么样的文件?内部由什么构成?虚拟机又是如何去识别它的?这篇文章就来学习 ...

  5. [深入理解Java虚拟机]第六章 Class类文件的结构

    在本章关于Class文件结构的讲解中,我们将以<Java虚拟机规范(第2版 )> (1999年发布,对应于JDK 1.4时代的Java虚拟机)中的定义为主线,这部分内容虽然古老,但它所包含 ...

  6. 详解Class类文件的结构(下)

    本文继续使用上次的Test.class文件,它是由下面单独的一个类文件编译而成的,没有包. 6. 索引(Index) 索引又分类索引.父类索引和接口索引集合,类索引(this_class)和父类索引( ...

  7. Java class类文件和类加载器详解以及代码优化

    JVM就是Java虚拟机,它是Java程序运行的载体. 计算机只识别0和1.Java是⾼级语⾔.⾼级语⾔编写的程序要想被计算机执⾏,需要变成⼆进制形式的本地机器码.能直接变成机器码的语义是C++,它的 ...

  8. Java线程类的继承结构

    Java多线程的设计上使用了代理的设计模式 https://edu.aliyun.com/course/36/learn?spm=0.0.0.0.YOzAsu#lesson/431课程链接 @Over ...

  9. java文件是什么_java类文件是什么?

    一.什么是Java类文件    Java类文件是Java程序的二进制表示形式.每一个类文件代表一个类或者接口.不可能在一个类文件中放入多个类或者接口.这样就使得无论类文件是在哪一种平台上生成,都可以在 ...

最新文章

  1. 安装H3C的各种问题
  2. 刀片服务器 如何增加硬盘,IBM为刀片服务器添加新SAS及固态硬盘
  3. Spring Cloud云服务架构 - HongHu云架构代码结构分析
  4. idea中的一个子模块中的pom文件带横线、maven为灰色
  5. int main()和void main()的区别
  6. android image 位移动画_ImageView自动来回循环移动,用到Animation
  7. MySQL双主机双Master方案测试
  8. 聚类分析 距离 matlab,用MATLAB做聚类分析
  9. Medoo Detele的使用:删除数据
  10. python爬取阳光问政
  11. 数据结构c语言版第二版(严蔚敏)第五章笔记
  12. IDEA解决开两个窗口问题
  13. 计算机管理 服务无响应,电脑任务栏假死点击没反应的解决方法(win7与xp)
  14. 学习VGG(网络讲解+代码)
  15. 平面最近点对问题求解—基于Java语言
  16. 谁来给移动互联网发牌照:安卓生态圈畸形发展
  17. 创建与使用DLL项目常见错误和解决办法
  18. AD16在走线至焊盘时不能自动定位到焊盘中心
  19. 漏刻有时数据大屏CSS样式表成长教程(2):九宫格图表背景自适应的解决方案
  20. (2020.1.2已解决)pyinstaller如何将外部数据csv一并打包

热门文章

  1. Executors工具类的相关方法
  2. ufo帧率测试网站_手机相机拍摄的视频帧率的测试方法
  3. 个人能用的短信平台有哪些?看这一篇就够了
  4. put短语(put短语归纳)
  5. 通信工程项目管理如何控制成本
  6. Google chrome插件 | pagenote 网页标记
  7. 软件工程c语言2000行代码,C语言教务管理系统(2000行代码)
  8. 【学习OpenCV4】案例1:Windows OpenCV C++语言开发环境搭建
  9. 百度云实现语音识别及语音合成
  10. 最新WIN平台服务器安全解决方案【青云原创】