JAVA字节码文件之第二篇(常量池)
君子生非异也 人气:0一、常量池的内容
一个java类中定义的很多信息都是由常量池来维护和描述的,可以将常量池看作是class文件的资源仓库,比如java类中定义的方法与变量信息。常量池中主要存储两类常量:字面量(文本字符串,final的常量)与符号引用(类和接口的全限定名,字段的名称和描述符,方法的名称和描述符
一、常量池的结构
二、常量池的分析
常量池(也称常量表):主版本号之后就是常量池的开始位置;java类所对应的常量池主要由常量池数量和常量池数组两部分组成,常量池数量是主版本号之后的两个字节;常量池数组在常量池数量之后,常量池数组中不同元素的类型,结构是不同的,所以该数组长度是不同的,但是数组中的每一种元素的第一个字节是标记位是一个u1类型,JVM在解析常量池时会根据这u1类型来获取元素的具体类型。
1、常量池元素的数量:
00 18(24):就是该class字节码文件的常量池数量; 常量池数组元素的个数=常量池数量-1;索引为0的位置暂不使用,目的是满足某些常量池索引值的数据在特定情况下需要表达,不引用任何一个常量池的含义。根本原因是索引为零也是一个常量,只是他不在常量池中,该常量对应null值,所以常量池的索引从1开始(#1)。
2、常量池数组
第一个元素:根据Constant pool 中 #1的描述可知该元素是无参的构造函数
0A(10):常量池元素数量之后的第一个字节,u1=10 对应
第一个u2(4):占两个字节即00 04;第二个u2(20):占两个字节即00 14;所以该常量池的第一个元素占五个字节即0A 00 04 00 14
第二个元素:根据 Constant pool 中#2的描述可知该元素是在类ByteCodeTest中一个int 类型 名字为num的变量,
09(9):第一个元素之后的第一个字节 ,u1=9 对应
第一个u2(3):占两字节00 03;第二个u2(15):占两个字节00 15;所以该常量池的第二个元素占五个字节即09 00 03 00 15
第三个元素:根据 Constant pool 中#3 可知该元素是该类的权限定名。
07(7):第二个元素之后的第一个字节07 ,u1=7 对应
u2(16):占两个字节00 16;所以该常量池的第三个元素占三个字节即07 00 16
第四个元素:根据 Constant pool 中#4 可知该元素是该Object类的权限定名。
07(7):第三个元素之后的第一个字节07 ,u1=7 对应
u2(17):占两个字节00 17;所以该常量池的第四个元素占三个字节即07 00 17
第五个元素:根据Constant pool 中#5的描述该元素是字符num
01(1):第四个元素之后的第一个字节01 ,u1=1 对应
u2(03):占两个字节00 03,表示utf-8格式的内容对应的长度是3个字节;u1:对应三个字节 6e 75 6d, 所以该常量池的第五个元素占6个字节即01 00 03 6e 75 6d;0x6e756d转字符串=num;
Hex转字符串工具
第六个元素:根据Constant pool 中#5的描述该元素是字符I
01(1):第五个元素之后的第一个字节01 ,u1=1 对应
u2(01):占两个字节00 01,表示utf-8格式的内容对应的长度是1个字节;u1(73):对应1个字节 49; 所以该常量池的第刘个元素占4个字节即01 00 01 49;49转十进制73;
根据ASCII字码表可知49=73=I;
其他元素分析方式与此相同就不再分析
三、JVM描述符
在jvm规范中,每个变量或字段都有描述信息,描述信息主要的作用是描述字段的数据类型,方法的参数列表(包括数量,类型与顺序)与返回值。
1、为了压缩字节码文件的体积,JVM对于基本数据类型和代表无返回值的void类型都用一个大写字符来表示,而对象类型用字符L加对象的全限定类名来表示
如下表示:B--byte,C--Char,D--double,F--float,I--int,J--long,S--short,Z--boolean,V--void,L--对象类型如Ljava/lang/String。
2、对于数组来说,每一个维度使用一个前置的[来表示,如Int[]表示为[I,String[][]表示为[[Ljava/kang/Stirng;
3、用描述符来描述方法时,用先参数列表后返回值的顺序来描述,参数列表按照参数的严格顺序放在一组()之内,如方法:String getNameById(int id,String name)的描述符为:(I,Ljava/lang/String) Ljava/lang/String;
public String getNameById(int id,String name){ return name; }
加载全部内容