java class文件结构

class文件格式:

image.png

测试文件:

package org.fenixsoft.clazz;

public class TestClass {

      private int m;

      public int inc() {

            return m + 1;

      }

}

(一)魔法数0XCAFEBABE:

image.png

(二)次 版本号0X00:

image.png

(三)主版本号0X33(十进制为49,对应java6):

image.png

(四)常量池0X16,表示后续有21个常量:

image.png

常量池项目类型表:

image.png

(4.1)常量池中第一个常量表:

image.png

CONSTANT_class_info型常量结构表:

image.png

name_index是一个索引值,它指向常量池中一个CONSTANT_utf8_info类型的常量,此常量代表这个类(或者接口)的全限定名。

测试用class_info标志位:

image.png

测试用class_info索引值,0X02指向常量池中第二个常量:

image.png

常量池中11种数据类型结构总表:

image.png

(4.2)第二项常量的标志位,0X01表示该常量类型为utf8_info类型,此处为常量池中第二个常量表:

image.png

utf8_info表的标志位:

image.png

第二项常量utf8_info表的长度0X1D(29)

image.png

class包名org.fenixsoft.clazz/Testclass;

image.png

继续往下分析。。。

(4.3)常量池中第三个常量表(class_info表):

image.png

标志位:

image.png

0X04表示指向常量池中第四个常量

image.png

(4.4)指向CONSTANT_utf8_info常量表,此为常量池中第四个常量表:

image.png

image.png

image.png

长度为16的java/lang/object

image.png

(4.5)常量池中第五个常量表(utf8_info表),值为m:

image.png

(4.6)常量池中第六个常量表(utf8_info表),值为I:

image.png

(4.7)常量池中第七个常量表(utf8_info表),值为<init>:

image.png

(4.8) 常量池中第八个常量表(utf8_info表),值为()V:

image.png

(4.9) 常量池中第九个常量表(utf8_info表),值为Code:

image.png

(4.10) 常量池中第十个常量表(Method_info表):

image.png

(4.11) 常量池中第十一个常量表(NameAndType_info表):

image.png

(4.12) 常量池中第十二个常量表(utf8_info表),值为LineNumberTable:

image.png

(4.13) 常量池中第十三个常量表(utf8_info表),值为LocalVariableTable:

image.png

(4.14) 常量池中第十四个常量表(utf8_info表),值为this:

image.png

(4.15) 常量池中第十五个常量表(utf8_info表),值为Lorg/fenixsoft/clazz/TestClass; :

image.png

(4.16) 常量池中第十六个常量表(utf8_info表),值为inc:

image.png

(4.17) 常量池中第十七个常量表(utf8_info表),值为()I:

image.png

(4.18) 常量池中第十八个常量表(CONSTANT_field_info表):

image.png

(4.19) 常量池中第十九个常量表(CONSTANT_NameAndType_info表):

image.png

(4.20) 常量池中第二十个常量表(utf8_info表),值为SourceFile:

image.png

(4.21) 常量池中第二十一个常量表:

image.png

至此,常量池的表结束。

(五)访问标志位表:

用于确定class是类还是接口,是否定义为public,是否定义为abstract,如果是类的话,是否被声明为final,等

image.png

image.png

0X21=ACC_PUBLIC | ACC_SUPER(0X0001 | 0X0020=0X0021)

(六)类索引,父类索引,接口索引集合:

类索引查找全限定名的过程:

image.png

类索引:

image.png

父类索引:

image.png

接口索引,本例中,没有接口,所以索引号为0:

image.png

(七)字段表结构:

image.png

字段表,批注1处,0X01表示该类只有一个字段,即计数器为1,批注2处0X02表示访问标识为ACC_PRIVATE,

批注3处0X05标识name_index指向常量池的第五个常量,即上面所列的CONSTANT_utf8_info字符串m,

批注4处0X06表示descriptor_index的值为0X06,指向常量池的第六个常量,即I,根据这些信息,我们可以推断,

源代码定义的是private int m,批注5处,0X00表示字段m的属性计数器为0,索引额外的信息描述为0X00:

image.png

(八)方法表:

方法表结构:

image.png

批注1处0X02表示方法表计数器容量为2,代表集合中有两个方法,标注2处0X01访问标志表示ACC_PUBLIC,

标注3处0X07表示名称索引值为7,对应<init>方法,标注4处0X08表示描述符索引为8,对应常量为()V,标注5处

0X01表示属性表计数器为1,表示此方法属性表集合有一项属性,属性名称索引为0X09,对应常量为Code,说明此属性是

方法的字节码

image.png

(九)属性表结构:

image.png

虚拟机规范的预定义属性

image.png

Code属性表结构:

image.png

java程序体的代码经过javac编译后,最终变为字节码存储在Code属性内(接口和抽象类没有Code属性),

attribute_name_index是一项指向CONSTANT_utf8_info型常量的索引,常量值固定为Code,attribute_length指示了属性值得长度,属性名称索引

和属性长度一共是6个字节,所以属性值得长度固定为整个属性表的长度减去6个字节。max_stack代表了操作数栈的最大深度,max_locals代表局部变量所需的存储空间,

code用来存储java源程序编译后生成的字节码指令,code_length代表字节码长度(虚拟机规范中规定一个方法不允许超过65535条字节码指令),

属性表集合(属性表总长度为0X2F):

image.png

标注1处max_stack代表了操作数栈最大深度值为1,标注2处max_locals本地变量表容量为1,

image.png

字节码长度为5

image.png

按照顺序,依次读入紧随的5个字节,字节码指令为0X2A,0XB7,0X00,0X0A,0XB1

image.png

翻译过程

读入2A,对应指令为aload_0

读入B7,对应指令为invokespecial

读入0X000A,这是invokespecial的参数

读入B1,对应的指令为return

字节码之后是异常表,异常表对于Code属性不不一定是存在的。异常表如图:

image.png

意义为如果字节码从start_pc到end_pc间出现了异常类型为catch_type或其子类异常,则转到handler_pc处理。

以下省略Exceptions属性,LineNumberTable属性,LocalVariableTable属性,SourceFile属性,ConstantValue属性,

InnerClass属性,Deprecated和Synthetic属性。


猜你喜欢

转载自blog.csdn.net/lxf20054658/article/details/77132300