java中class类文件结构

类文件是java程序编译后产生的文件,要了解java虚拟机,了解它的类文件结构是必不可少的。


类文件简介

首先我们要清楚java的class类文件是以8字节为基础的二进制流,什么叫以8位字节为基础,就是如果你是16,32位或者以上的东西,它都会分割开来存储的,而且每个数据之间没有任何的分割符号,像一家人一样紧凑的挨在一起。
这种文件中包含了虚拟机指令集,符号表还有一些辅助信息。它的数据类型只有两种:无符号数和表:
无符号数:用u1,u2,u4,u8分别表示1字节,2字节,4字节,8字节的无符号数,可以用来描述一些数值,索引引用等等。
表:由多个无符号数和表组成的一种复合数据类型。由于整个class文件就是由这些东西组成的,所以class文件本身就是一个表。习惯性的以_info结尾。

下面我们弄一张图片看看class文件的整体结构,尽量让大家有个印象,不求记住,只求了解就行。
在这里插入图片描述

刚开始我看到这些东西也是很陌生,很头疼,但你仔细看,其中的常量池在我写的虚拟机内存结构就提及过了。不记得不要急,我在这里一一谈一谈我自己的理解。
下面这张图是一个程序的二进制文件,把它转成了十六进制,便于观察。可以清楚的看到,每两个字符一起组成了一个字节。
在这里插入图片描述

一:魔数和版本号:

magic:魔数,前4个字节都是描述魔数的,这个东西是指区分能够被java虚拟机识别的class文件,值位CAFEBABE,如果肉麻的话,可以理解成“咖啡宝贝”。

minor_version:此版本号,占2个字节,分别是5,6字节。

major_version: 主版本号, 占2个字节,分别是7,8字节。 这部分了解一下就行,没有多大意义。

二:常量池计数器和常量池:

常量池在前面的内存区域已经涉及到了一点点了。在版本号之后呢,有一个常量计数器,因为常量的值不确定,得要知道有多少个常量对不对。而且常量的计数是从1开始的。占2个字节。
下面就是常量池中的东西了。
在这里插入图片描述
字面量相信大家都已经有所了解,我介绍一下符号引用吧。
完全限定名:又称作绝对名称,一般描述类和接口的名称,比如一个类Thread,全限定名就是java.lang.Thread,但是非限定名不同他可以省略一点点,就是Thread。
描述符:描述符是一个描述字段或方法的类型的字符串。
字段描述符:是一个表示类、实例或局部实例变量的语法符号。
方法描述符:描述一个方法所需的参数和返回值信息,即包括参数描述符和返回描值述符;
下面是描述符中表示基本类型的符号:
在这里插入图片描述
int实例变量的描述符是"I";这从这个表中应该可以看出来。

java.lang.Object实例描述符是"Ljava/lang/Object;";

double的三维数组"double d[][][];“的描述符为”[[[D";

接下来就是常量池中的常量项及其结构了:
在这里插入图片描述
在这里插入图片描述

从上面这些东西可以看到,常量池中的每一常量(符号引用或者字面量)都是以上途中14种类型中的一种。我们举一个例子来理解一下:

07 00 02 01 假设class文件中的某一十六进制码段是这个,那么首先看07,这个首先看的07就是标志位(tag),然后在上面 的表中找到07标志位对应的数据类型CONSTANT_class_info,这个数据类型的索引占2个字节,然后接下来2个字节00 02就是一个索引,指向第二个常量,0x01表 示CONSTANT_Utf8_info,差不多就是字符串,就是一个类或者接口的名字了,以此类推,后面的十六进制码我们 可以一一推出来。

三:访问标志

接着常量池后面的2个字节表示访问标志,含义见下表
在这里插入图片描述
这个根据十六进制码找到对应的含义就行。包括类和接口的访问类型,是否为public等等。

四:类索引,父类索引,接口索引

类索引:占2个字节,表示对本类的描述。

父类索引:占2个字节,表示对父类的描述。

接口索引:头两个字节表示实现的接口数,然后紧跟着接口列表。

每一个索引都要对应到常量数据中的信息。

五:字段表集合

接着接口索引集合后面的就是字段表的个数,然后就是字段表。个数任然占有两个字节。

字段表用于描述接口或者类中声明的变量。字段包括类级变量以及实例级变量。主要包括以下信息:

  • 字段的作用域(public、private、protected修饰符)
  • 实例变量还是类变量(static修饰符)
  • 可变性(final)
  • 并发可见性(volatile)
  • 可否被序列化(transient)
  • 字段数据类型(基本类型,对象,数组)
  • 字段名称
    字段表结构:
    在这里插入图片描述

1:access_flags:
在这里插入图片描述
2:name_index:是对常量池的索引
3:descripto_index:也是对应常量池的索引
在这里插入图片描述
字段表都包含的固定数据项到descriptor_index为止就结束了,不过在descriptor_index之后跟随着一个属性表集合用于存储一些额外的信息,字段都可以在属性表中描述零至多项的额外信息。属性表等会儿后面会提到。

六:方法表集合

和字段表集合其实差不多,也有对应方法表结构,紧跟着字段表后面的就是方法的个数,然后就是方法表。

方法表结构:
在这里插入图片描述
在这里插入图片描述
方法表中·的方法代码具体存在了属性中,下一标题会讲到的。这样的方法表集合也就和字段表差不多了,虽然表中有一定的区别。

七:属性表集合

属性这一块就是一个大块了。最然在最后谈属性表,但是属性表在前面的许多地方都有的,比如字段表,方法表。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对于每个属性,它的名称需要从常量池引用一个CONSTANT_Utf8_info类型的常量来表示。

属性表结构:

1:Code属性:
在这里插入图片描述
attributenameindex:表示指向的CONSTANT_Utf8_info类型常量的值固定为Code

attribute——length:表示属性表的总长度。

max_stack:这个在上一篇文章讲过了,我说过在编译的时候最大的操作数栈就已经确定了。

max_locals:最大的存储空间,以slot(内存槽为单位),也是在之前的文章说过了,可以去看一看。

code_length:表示核心代码长度。

code:存储核心代码,它是一种指令集每个占1个字节。
2:异常表
异常表结构:
在这里插入图片描述
如果当字节码在第start_pc行到end_pc行之间(不含第end_pc行)出现了类型为catch_type或其子类异常(catch_type为指向一个CONSTANT_Class_info型常量的索引),则转到第handler_pc行继续处理。当catch_type的值为0时,代表任意异常情况都需要转向到handler_pc处进行处理。

  • 如果try语句块中出现属于Exception或其子类的异常,则转到catch语句块处理。
  • 如果try语句块中出现不属于Exception或其子类的异常,则转到finally语句块处理。
  • 如果catch语句块中出现任何异常,则转到finally语句块处理。
  • 更详细的可参考异常处理机制;
    3:Exception属性
    在这里插入图片描述
    Exception属性的作用是列举出方法中可能抛出的受查异常, 也就是方法描述时在throws关键字后面列举的异常。

接下来我说的属性我没有详细介绍,个人感觉对我自己暂时没有啥帮助。哈哈哈

LineNumberTable属性

LineNumberTable属性用于描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。
在这里插入图片描述

linenumberinfo包括startpc和line_number,对应字节码行号和源码行号

LocalVariableTable属性

在这里插入图片描述
LocalVariableTable属性用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系。

SourceFile属性

SourceFile属性用于记录生成这个Class文件的源码文件名称。

ConstantValue属性

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

InnerClasses属性

InnerClasses属性用于记录内部类与宿主类之间的关联。

Deprecated及Synthetic属性

两个属性都属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念。Synthetic代表字段或者方法并不是有Java源码直接产生的,而是由编译器自行添加的。

StackMapTable属性

它是一个复杂的变长属性,位于Code属性的属性表中。会在虚拟机类加载的字节码验证阶段被新类型检查验证器(Type
Checker)使用,目的在于代替以前比较消耗性能的基于数据流分析的类型推导验证器。一个方法的Code属性最多只能有一个StackMapTable属性。

Signature属性

用于记录泛型签名信息。

BootstrapMethods属性

位于类文件的属性表中。用于保存invokedynamic指令引用的引导方法限定符。

以上是我对类文件结构的理解,后面的属性因为某些知识的缺乏,暂时还没有理解透,后期我会补上,大家暂时看看我的文章有没有问题,希望大家多提提意见,如果实在还看不懂,我会更新一篇具体的看解析字节码的文章。

posted @ 2019-08-02 12:23  ongbo  阅读(37)  评论(0)    收藏  举报