JAVA的class文件

1.Class文件结构

jvm规范规定,Class文件采取一种类似C语言结构体的伪结构来存储数据,这种数据结构只有两种数据类型:无符号数和表。

  1. 无符号数属于基本数据类型,以u1,u2,u4,u8分别代表1个字节、2个字节、4个字节和8个无符号数。无符号可以描述数字、索引、引用、数量值或者按照utf-8编码构成的字符串值。
  2. 表是有无符号数和其他表作为数据项的复合数据类型,所有表都以_info结尾。
    在这里插入图片描述

1.1 魔数与Class版本

  1. 每个Class文件都以4个字节的魔数开头,它唯一的作用就是确定该class文件是否能被jvm接受。值为:0xCAFEBABE。
  2. 紧接着是4个字节的魔数是声明class版本号的。

1.2 常量池

常量池是一个class的资源仓库。常量池入口需放置一个u2的常量池容量计数(从1开始,0代表不引用任何常量)。
常量池有两大类:

  1. 文本字符串和声明是final的常量值
  2. 编译方面的概念:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
    java编译没有连接这一步,无法生成字段和方法的内存布局。jvm运行时,需要从常量池获得对应的符号引用,在类创建时或运行时、解析、翻译到具体的内存地址中。

1.3 访问标识

2个字节,标识类或接口的层次的范文信息,包含这个class是类还是接口;是否是public 是否是abstract,是否声明为final。

在这里插入图片描述

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

类索引和父类索引都是u2类型,而接口索引集合是一组u2类型的集合(当然在这之前有一个u2类型的计数)。

  1. 对于类索引和父类索引u2类型的索引值只想一个类型为CONSTANT_Class_info的类描述符,通过CONSTANT_Class_info类型对的索引值可以找到定义在CONSTANT_utf8_info类型的常量中的全限定名字符串。
  2. 对于接口索引集合,入口的一个u2接口计数,没有实现任何接口为0,后面的接口表不占用任何字节。

1.5 字段表集合

字段表用来描述接口或类中的成员变量,但不包括局部变量。字段表结构如下:

类型名称数量
u2access_flag1
u2name_index1
u2descriptor_index1
u2attributes_counts1
u2attributesattibutes_count

访问标识

标识名称标识值含义
ACC_PUBLIC0X0001是否为public
ACC_PRIVATE0X0002是否为private
ACC_PROTECTED0X0004是否为protected
ACC_STATIC0X0008是否为static
ACC_FINAL0X0010是否为final
ACC_VOLATILE0X0040是否为volatile
ACC_TRANSIENT0X0080是否为transient
ACC_SYNITHETIC0X1000是否由编译器自动生成
ACC_ENUM0X4000是否为enum

name_index和descriptor_index 分别代表字段的简单明和描述索引。

全限定名:就是将类的全类名中的.换成/,如org/fenixsoft/calss/TestClass。
简单名:没有类型和参数修饰的方法或字段。
描述符:1.描述字段的类型;2.方法的参数列表(数量、类型和顺序)和返回值。对于基本类型返回值和空都用大写字母表示;而对象用全限定名表示;对于数组则在原有的标识符前置[(多维数组就多个)。用描述符描述方法时:先参数列表,并按顺序放在一个()内,然后返回值。如方法void inc() 描述符为()V。
属性表集合:用来描述存储一些额外的信息,字段都可以在描述0-n个额外信息。如字典声明为static final 会产生ConstantValue属性。

字段表结合不会描述从父类中继承的字段,但由可能列出原本java代码中不存在的字段,譬如在内部勒种为了保持对外部类的访问性。

1.6 方法表集合

方法表结构和字段表一样。

类型名称数量
u2access_flag1
u2name_index1
u2descriptor_index1
u2attributes_counts1
u2attributesattibutes_count

访问标识与方法不同,少了volatile和transient

标识名称标识值含义
ACC_PUBLIC0X0001是否为public
ACC_PRIVATE0X0002是否为private
ACC_PROTECTED0X0004是否为protected
ACC_STATIC0X0008是否为static
ACC_FINAL0X0010是否为final
ACC_SYNCHORINIZED0X0020是否为synchronized
ACC_BRIDGE0X0040是否为编译器产生的桥接方法
ACC_VARARGS0X0080是否接受不定参数
ACC_NATIVE0X0100是否为native方法
ACC_ABSTRACT0X0400是否为abstract方法
ACC_STRICTFFP0X0800是否为strickfp
ACC_SYNTHETIC0X1000是否为编译器生成

特别注意:方法里的代码存储在方法属性集合中一个名为Code的属性里面。

如果父类的方法没有被子类覆盖,方法表集合不会有父类的任何信息。但可能有编译器自动添加方法。如clinit和init方法。

1.7 属性表集合

class文件、字段表、方法表都可以存在属性表。
属性表不要求严格的顺序,不重名。任何人实现的jvm都可以写入自己定义的属性信息。
对于每个属性他的名字需要从常量池中引用一个constant_utf8_info常量表示。
属性表j基本结构

类型名称数量
u2attribute_name_index1
u4attribute_length1
u1infoattribute_length
属性名使用位置含义
Code方法表java代码编译生成的字节码指令
ConstantValue字段表final关键字定了的常量
Deprecated方法表deprecated的方法和字段
Exceptions方法表方法抛出的异常
EnclosingMethod类文件晋档一个类为局部类或匿名内部类才拥有这个属性,这个属性拥有标明这个歌类所在的外围方法

1.7.1 Code属性

并非所有方法表都拥有code属性表,比如接口和abstract方法。

1.7.2 Excetions属性

列举出方法可能抛出的受检异常。

1.7.3 LineNumberTable属性

拥有描述java源码和class字节码行号之间的对应关系。javac 分别使用 -g:none或-g:lines 取消和要求生成这项信息。

1.7.4 LocalVariableTable属性

LocalVariableTable属性用于描述栈帧中局部变量表与java源码定义变量的关系。javac中 -g:none和-g:vars选项取消或生成。

1.7.5 SourceFile属性

SourceFile用于标记生成Class文件的源码名称。

1.7.6 ConstantValue属性

HotSpot认为 final static 更符合常量语义,。

1.7.7 InnerClass属性

该属性用来记录内部类和宿主类的福暗恋。

1.7.8 Deprecated和Synthetic

1.7.9 StackMapTable属性

复杂的变化属性,位于Code属性中。省略在运行期间通过数据流分析去却字节码的行为逻辑合法性的步骤,二是在编译阶段将一系列的验证类型直接记录在class文件中,提升字节码验证性能

1.7.10 Signature属性

Signature属性会为它记录泛型签名和信息,java语言是擦除实现的伪泛型。java的反射API能够获取泛型类型,最终的数据来源就是这个属性。

1.7.11 BootstrapMethods属性

参考

  1. https://www.jianshu.com/p/247e2475fc3a
  2. 周志明,深入理解Java虚拟机:JVM高级特性与最佳实践,机械工业出版社
  3. https://www.cnblogs.com/paddix/p/5282004.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值