本章节继续学习常量池相关信息
常量池
接上一章节
CONSTANT_String_info
CONSTANT_String_info常量表示java.lang.String字面量,结构如下:
可以看出,CONSTANT_String_info本身并不存放字符串数据,只存了常量池索引,这个索引指向前面讲的CONSTANT_Utf8_info常量。ConstantStringInfo结构体位于cp_string.go文件中:
因为指向stringIndex指向的是常量池索引,所以要获取string字面值,还需要去ConstantPool中读取数据,下面编辑constant_pool.go文件,添加通过索引值读取ConstantUtf8Info的方法:
ClassFile.class中main()方法中使用的字符串class文件如下:
有上图可以看出,tag为0x08,表示CONSTANT_String_info,tag占一个字节。后面两个字节0x0034是常量池索引,转换成十进制为52,那再看一下常量池第52个:
再详细看下class文件,第一个字节tag为0x01,表示CONSTANT_Utf8_info。后面两个字节是length:0x000D,转换成十进制为13。最后13个字节为0x48656C6C6F2C20576F726C6421,对应的ASCII码正是Hello, World!。
CONSTANT_Class_info
CONSTANT_Class_info常量表示类或者接口的符号引用,结构如下:
和CONSTANT_String_info类似,name_index是常量池索引,指向CONSTANT_Utf8_info常量,相关代码位于cp_class.go文件中:
ClassFile.class类名的class文件如下:
有上图可以看出,tag为0x07,表示CONSTANT_Class_info,tag占一个字节。后面两个字节0x0037是常量池索引,转换成十进制为55,再看下常量池第55个:
再详细看下class文件,第一个字节tag为0x01,表示CONSTANT_Utf8_info。后面两个字节是length:0x0013,转换成十进制为19。最后19个字节为0x636E2F6469646164752F436C61737346696C65,对应的ASCII码正是cn/didadu/ClassFile。
CONSTANT_NameAndType_info
CONSTANT_NameAndType_info给出字段或方法的名称和描述符。CONSTANT_Class_info和CONSTANT_NameAndType_info加在一起可以唯一确定一个字段或者方法。,其结构如下:
字段或方法名由name_index给出,字段或方法的描述符由descriptor_index给出。name_index和descriptor_index都是常量池索引,指向CONSTANT_Utf8_info常量。字段和方法名就是代码中出现的字段或者方法的名字,这个很好理解。重点看一下他们的描述符,Java虚拟机规范定义了一种简单的语法来描述字段和方法,具体规则如下:
- 类型描述符
- 基本类型byte、short、char、int、long、float和double的描述符是单个字母,分别对应B、S、C、I、J、F和D。要注意的是,long的描述符是J而不是L。
- 引用类型的描述符是L+类的完全限定名+分号。
- 数组类型的描述符就是[+数组元素类型描述符。
- 字段描述符就是字段类型的描述符。
- 方法描述符是(分号分割的参数类型描述符)+返回值类型描述符,其中void返回值由单个字母V表示。
看到这里有点疑惑了,这里说的字段、方法的名称和描述与之前讲的字段表、方法表有什么区别。经过一番研究,具体过程就不详述了,参照ClassFile2.class的class文件,会发现端倪。得出一个初步的结论,字段表、方法表表示的是类成员变量和方法的定义,而此处的CONSTANT_NameAndType_info出现在局部方法中,表示局部变量的定义和方法的调用。
相关代码位于cp_name_and_type.go文件中:
从class文件中挑一个CONSTANT_NameAndType_info看看:
看下class文件,第一个字节tag为0x12,表示CONSTANT_NameAndType_info。后面两个字节是0x003B,转换成十进制为59(name_index),再后面两个字节是0x003c(descriptor_index),转换成十进制是60。
找出常量池第59个、60个:
就不分析了,最终可以看出该字段的名称和描述分别为out、Ljava/io/PrintStream,表示变量的名称为out,类型是java.io.PrintStream,对应ClassFile.java中System.out的使用。
下节继续。。。