前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java虚拟机--Class文件结构

Java虚拟机--Class文件结构

作者头像
SuperHeroes
发布2018-05-22 16:25:44
7470
发布2018-05-22 16:25:44
举报
文章被收录于专栏:云霄雨霁云霄雨霁云霄雨霁

Class文件是一组以8位字节为基础单位的二进制字节流,各个数据项目严格按照顺序排列在Class文件中,中间没有任何分隔符

如果一个数据需要8位以上的空间,则会按照高位在前(最高为字节在地址最低位,最低位字节在地址最高位)的方式分割成若干个8位字节进行存储。

Class文件只有两种数据类型:无符号数和表。

  • 无符号数:属于基本数据类型,以u1, u2, u4, u8来分别代表一个字节、两个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照utf-8编码构成的字符串值。
  • :表是由多个无符号数或其他表作为数据项的复合数据类型,所有表都习惯性的以“_info"结尾。表用于描述有层次关系的复合结构数据,整个class文件本质上就是一张表。

魔数与Class文件版本:

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

紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本号,第7和第8字节是主版本号。

常量池:

紧接着主次版本号之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一。

由于常量池中常量的数量不固定,所以在常量池的入口需要放置一项u2类型的数据,代表常量容器计数值。与Java语言习惯不同,它是以计数值1开始的。

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

字面量:接近Java语言层面的常量的概念,如文本字符串、声明为final的常量值等。

符号引用:属于编译原理方面的概念,包括三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

常量池中每一项常量都是一个表,表开始的第一位是一个u1类型的标置位,代表当前这个常量属于哪种常量类型。

访问标志:

常量池结束后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或接口的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。

类索引、父索引、接口索引集合:

类索引和父索引都是一个u2类型的数据,而接口索引集合是一组u2类型数据的集合,Class文件中由这三项数据确定类的继承关系。

类索引用于确定这个类的全限定名,父索引用于确定这个类的父类的全限定名。接口索引集合用来描述这个类实现的接口,这些被实现的接口按照implements语句(如果本身是接口,则应该是extends语句)的顺序排列。

字段表集合:

字段表用于描述接口或类中声明的变量。字段包括类级变量和实例级变量,但不包括方法内部声明的局部变量。

一个字段需要保存哪些信息?字段的作用域(public、protected、private)、是实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile)、可否被序列化(transient)、字段的数据类型(基本类型、对象、数组)、字段名称。

字段表结构依次包括:访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor)、属性表集合(attribute_info)。除了属性表集合是表,其他类型都是一个u2类型。

  • 访问标志(字段修饰符):其中存储的是一个字段访问标志,比如字段如果为public,则存储ACC_PUBLIC。
  • 名称索引:存储的是常量池引用,代表着字段的简单名称。
  • 描述符索引:存储字段和方法的描述符,通过描述符表示字符来定义,如:java.String toString()方法的描述符为:“()Ljava/lang/String”。
  • 属性表集合:字段表后可以跟一个属性表集合用于存储一些额外信息,字段可以在属性表中描述零至多项额外信息。

方法表集合:

方法表结构同字段表一样,依次包括了:访问标志、名称索引、描述符索引、属性表集合这几项。除了属性表集合是表,其他类型都是一个u2类型。

方法表中没有保存方法体,方法体存放在方法属性表中的“Code”属性里面。属性表是Class文件最具扩展性的一种数据项目。

属性表集合:

Class文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景的专有信息。《Java虚拟机规范(Java SE7)》中预定义了21项属性。

1、Code属性

Java方法体中的代码经过javac编译器处理后,最终变为字节码指令存储在Code属性内。

2、Exceptions属性

列举出方法中可能抛出的受查异常,也就是方法描述时在throws关键字后面列举的异常。

3、LineNumberTable属性

用于描述Java源码行号和字节码行号(字节码偏移量)之间的对应关系。该属性不是必须的,如果选择不生成该属性,对程序运行时最主要的影响是抛出异常时不会显示出错行号,也无法按照源码行设置断点。

4、LocalVariable属性

用于描述栈帧中局部变量表中的变量与Java源码中定义变量之间的关系,它不是必须的属性。如果选择不生成该属性,在调试期间无法根据参数名称从上下文获得参数值。

5、SourceFile属性

用于记录生成这个class文件的源文件名称。该属性也是可选的。如果不生成该属性,当抛出异常时堆栈中不会显示出错代码所属的文件名。

6、ConstantValue属性

通知虚拟机自动为静态变量赋值。只有被static关键字修饰的变量才可以使用这项属性。

变量赋值问题: 对于非static的变量(即实例变量)的赋值实在实例构造器<init>方法中进行的; 对于static变量(类变量),有两种方式选择:在类构造器<clinit>方法中或者使用ConstantValue属性。目前Sun Javac编译器的选择是:如果同时使用final和static来修饰一个变量(这里称为常量更贴切),并且这个变量的类型是基本数据类型或String时,就生成ConstantValue属性来初始化;如果这个变量没有被final修饰,或者并非基本类型及字符串,则在<clinit>方法中进行初始化。

7、InnerClasses属性

用于记录内部类和宿主类之间的关联。如果一个类中定义了内部类,那编译器就会为它和它的内部类生成InnerClasses属性。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 魔数与Class文件版本:
  • 常量池:
  • 访问标志:
  • 类索引、父索引、接口索引集合:
  • 字段表集合:
  • 方法表集合:
  • 属性表集合:
    • 1、Code属性
      • 2、Exceptions属性
        • 3、LineNumberTable属性
          • 4、LocalVariable属性
            • 5、SourceFile属性
              • 6、ConstantValue属性
                • 7、InnerClasses属性
                相关产品与服务
                对象存储
                对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档