目录
2.1 UTF-8 编码的字符串 CONSTANT_Utf8_info
2.4 字符串字面量 CONSTANT_String_info
2.5 字段引用信息 CONSTANT_Fieldref_info
2.6 方法引用信息 CONSTANT_Methodref_info
2.7 接口方法引用信息 CONSTANT_InterfaceMethodref_info
2.8 名称及类型信息 CONSTANT_NameAndType
4. 类索引(This_class),父类索引(Super_class),接口索引集合(Interfaces)
1. Class文件结构简介
不管是大端模式还是小端模式,cpu在内存的读写数据都是从低地址开始到高地址; 大端模式就是先读到的是高位(低地址存高位,高地址存低位),小端模式就是先读到的是低位(低地址存低位,高地址存高位)。
大端小端产生的根本原因:在计算机中,内存之间不能之间传输数据,需要通过寄存器转,内存的存储单元是字节,但是寄存器是多字节的,于是就有了高位、低位之分,不同的厂家生产的CPU的标准不同,有的用大端(绝大多数),有的用小端,大端小端也就随之而来。
JDK的bin目录下,有个javap的工具,可以在命令行窗口中利用此工具显示出Class文件的结构,便于分析class字节码文件。
class文件结构简介:
class文件的结构就如上图所示,固定顺序,固定格式,以字节为单位,字节之间不存在任何空隙,对于超过8位的数据,将高位放在class文件的前面,低位放在后面(这是大端模式),否则jvm无法正确解析class文件。
magic:魔数,u4表示4个字节,就是一个文件类型的标志,表明此文件是哪种类型,png、TXT,等等,java class文件的魔数固定是0xCAFEBABE,虚拟机加载class文件时,会先检查这个部分,如果不是这个值,虚拟机拒绝加载该文件。
minor_version:次版本号;
major_version:主版本号; 主次版本号构成版本号,class文件的版本号对应着jdk的版本号,比如:45(1.1)、46(1.2)、47(1.3)、48(1.4)、49(1.5)、50(1.6)、51(1.7),可以看到jdk版本每增加0.1,版本号就加1,低版本JDK编译生成的class文件,可以被高版本的JRE执行,但是反之,则不行,虚拟机加载class文件之前,会先查看class文件的版本是否在自己的支持范围之内。
constant_pool_count:常量池的大小,从1开始计数,比如count = 11,那么元素共10个,1~10,第0个单元空出来;
constant_pool:常量池,是数组形式,由字面常量 和 符号引用 组成,保存字面常量和符号引用,符号引用保存的是引用的全局限定名,所以保存的是字符串;
access_flags:当前类的访问权限;
this_class:当前类的全局限定名在常量池中的索引(常量池以数组方法存储,索引即为下标);
super_class:当前类的父类的全局限定名在常量池中的索引;
interfaces_count:当前类实现的接口数目;
interfaces[ interfaces_count ]:这些接口的全局限定名在常量池中的索引的数组;
fields_count:字段的数量;
fields[ fields_count ]:
结构图如下:
重点说明:
用下面这个类的代码作为分析的例子:
public class Test{
public int a = 3;
static Integer si = 6;
String s = "Hello world!";
public static void main(){
Test test = new Test();
test.a = 8;
si = 9;
}
private void test(){
this.a = a;
}
}
2、常量池
上图是常量池的结构;
常量池主要存放字面量 和 符号引用,符号引用包括:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
常量池的存储形式可理解为数组,每个元素又是一个结构(标识(u1类型,一个字节),元素内容),每个元素都有一个索引值,通过这个索引值就可以定位数组中的某个元素,元素的类型有很多,通过标识位来区分,如下表(可以理解常量池主要存储字面量和符号引用了吧!):