注意一下讲解都是基于该Class文件结构;
任何一个Class文件都对应着一个类或者接口的定义信息;
Class文件是一组以8位字节为基础单位的二进制流;
Class文件存储结构:只有两种数据类型:无符号数和表
无符号数属于基本数据类型:以u1、u2、u4、u8来代表一个字节、两个字节、三个字节、四个字节的无符号数
作用:可以用来描述数量值、索引引用、数字或者按照utf-8编码构成的字符串值;
是由无符号数和其他表作为数据项构成的复合数据类型,所有表都一般以"_info"结尾;
Class文件的头四个字节成为魔数;
作用:确定这个Class文件能否被虚拟机接受
##2.Class文件版本号 ##
对应上图第二、三数据项:minor_version(次版本号) 、Major_Version(主版本号)
java版本号是从45开始的
他是Class文件结构中和其他项目关联项目最多的数据类型,也是占用Class文件空间最大的数据项目之一;
由于常量池中的常量数量是不固定的,为此常量池入口需要放置一个u2数据类型的数据,代表常量池容量计数值(Constant_pool_count)
注意:常量池容量计数从1开始的比如:常量池计数对应的u2类型数据是0x0016对应的十进制为22,表示常量池中有22个常量(索引范围就是1-21);
常量池中主要用于存放两大类常量:字面量(比如文本字符串、声明为final的常量等)和符号引用
符号引用包含以下三类常量:
常量池中每一项常量都是一个表;到JDK1.7共有14中表类型
这14中表结构都有一个共同点:表开始的第一位是一个u1类型的标志位(取值对应上图的标志列),用于判断该常量时哪种表类型;对应Class文件的结构图中(偏移量地址:0x0000000A)的0x07,即说明该常量时CONSTANT_Class_info类型的表,该常量是类或者接口符号引用;
以CONSTANT_Class_info表结构为例:
u1是上面我们说的标志位,name_index是一个索引值指向常量池中一个CONSTANT_String_info类型常量,此常量代表了一个这个类或者接口全限定名;即偏移地址(0x0000000B)为0x0002,换算成十进制2(表示指向常量中第2个常量),该常量的标志位即偏移地址:0X0000000D)为0x01,即标志为1,通过查看上面的表类型图说明该常量是CONSTANT_Uft8_info类型的常量;
常量池结束后紧接着两个字节表示访问标志,用于标志类或者接口层次的访问信息包括:
具体标志位:
![](http://linleslie.test.upcdn.net/%E6%B7%B1%E5%85%A5java%E8%99%9A%E6%8B%9F%E6%9C%BA/16%E3%80%81%E8%AE%BF%E9%97%AE%E6%A0%87%E5%BF%97%E4%BD%8D.
由于是两个字节,所有有16个标志位,当前只定义了8个标志位,未使用的标志位为0;
由这三项数据用于确定类的继承关系;
类索引:确定这个类的全限定名;
父类索引:这个类的父类全限定名,java不允许多继承,索引除了Object没有父类,其父类索引为0 外,其他任何类都有父类索引
接口索引:用于描述这个类实现接口的全限定名
this_Class、Super_Class时一个u2类型的数据,而interface_Class是一组u2类型数据集合;
查找类、父类全限定名:
查找实现接口
入口第一项,u2类型的连个字节表示实现的接口数量,后面的这N个数量的u2类型索引值,它们各自指向一个CONSTANT_Class_info的类描述符常量,通过该常量中的索引值可以找到CONSTANT_Utf8_info类型常量中的全限定接口名字符串
字段表集合前是一个u2类型的数据:表示有多少个字段表,紧接着就是具体的所有字段表;
字段表:用于描述接口和类中定义的成员变量,成员变量包括的信息:
这些通过一个u2类型的访问标志来实现(和类访问标志位大同小异);
字段表结构:
紧接着是两项索引值:name_index、descriptor_index都是对常量池的引用,表示字段名、字段描述符;
关于成员变量简单名称、类全限定名以及成员变量、方法描述讲解:
简单名:即变量名、方法名
类全限定名:把类全名如:java.lang.Object中的“.”换成了“/”java/lang/Object
成员变量描述符:描述变量类型
方法描述符:方法的参数列表(包括数量、类型、顺序)和返回值
基本数据类型(boolean、long除外)和无返回值的void类型用其首字母大写表示
对象类型使用大写L加类的全限定名
:如
数组的每一维度使用一个[表示如:
String[][]----->[[Ljava/lang/String
方法描述符如:
public char test(String[][] s,int b,long c,Int d){}
对应描述符为:([[Ljava/lang/StringIJI)C
字段表集合不会列出从超类或者父接口中继承而来的成员变量;
和字段表结构大同小异:
有点区别的就是访问标志:
方法中的代码经编译器编译成字节码指令后存放在属性表中的名为"Code"的属性里;
注意:父类的方法在子类中没有被重写,不会出现子类方法表集合中;
48)]
有点区别的就是访问标志:
[外链图片转存中…(img-kzt10Njt-1594971298850)]
方法中的代码经编译器编译成字节码指令后存放在属性表中的名为"Code"的属性里;
注意:父类的方法在子类中没有被重写,不会出现子类方法表集合中;