常量池中各数据项类型详解
3)CONSTANT_Integer_info
一个常量池中的 CONSTANT_Integer_info 数据项, 可以看做是CONSTANT_Integer类型的一个实例。 它存储的是源文件中出现的int型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为3, 也就是说, 当虚拟机读到一个tag值为3的数据项时, 就知道这个数据项是一个CONSTANT_Integer_info, 它存储的是int型数值的值。 紧挨着tag的下面4个字节叫做bytes, 就是int型数值的整型值。 它的内存布局如下:
下面以示例代码进行说明, 示例代码如下:
package com.jg.zhang;
public class TestInt {
void printInt(){
System.out.println(65535);
}
}
将上面的类生成的class文件反编译:
D:\Workspace\AndroidWorkspace\BlogTest\bin>javap -v -c -classpath . com.jg.zhang.TestInt
下面列出反编译的结果, 由于反编译结果较长, 我们省略了大部分信息:
..................
..................
Constant pool:
..................
..................
#21 = Integer 65535..................
..................{
..................
..................void printInt();
flags:
Code:
stack=2, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #21 // int 65535
5: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
8: return
LineNumberTable:
line 6: 0
line 7: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/jg/zhang/TestInt;
}
上面的输出结果中, 保留了printInt方法的反编译结果, 并且保留了常量池中的第21项。 首先看printInt方法反编译结果中的索引为3 的字节码指令:
3: ldc #21 // int 65535
这条ldc指令, 引用了常量池中的第21项, 而第21项是一个 CONSTANT_Integer_info, 并且这个CONSTANT_Integer_info存储的整型值为65535 。
4)CONSTANT_Float_info
一个常量池中的CONSTANT_Float_info数据项, 可以看做是CONSTANT_Float类型的一个实例。 它存储的是源文件中出现的float型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为4, 也就是说, 当虚拟机读到一个tag值为4的数据项时, 就知道这个数据项是一个CONSTANT_Float_info, 并且知道它存储的是float型数值。 紧挨着tag的下面4个字节叫做bytes, 就是float型的数值。 它的内存布局如下:
举例说明, 如果源文件中的一句代码使用了一个float值, 如下所示:
void printFloat(){
System.out.println(1234.5f);
}
那么在这个类的常量池中就会有一个 CONSTANT_Float_info与之相对应, 这个CONSTANT_Float_info的形式如下:
代码反编译结果如下:
Constant pool:
.............
.............#29 = Float 1234.5f
............
............{
............
............void printFloat();
flags:
Code:
stack=2, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #29 // float 1234.5f
5: invokevirtual #30 // Method java/io/PrintStream.println:(F)V
8: return
LineNumberTable:
line 10: 0
line 11: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/jg/zhang/TestInt;
}
5)CONSTANT_Long_info
一个常量池中的CONSTANT_Long_info数据项, 可以看做是CONSTANT_Long类型的一个实例。 它存储的是源文件中出现的long型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为5, 也就是说, 当虚拟机读到一个tag值为5的数据项时, 就知道这个数据项是一个CONSTANT_Long_info, 并且知道它存储的是long型数值。 紧挨着tag的下面8个字节叫做bytes, 就是long型的数值。 它的内存布局如下:
举例说明, 如果源文件中的一句代码使用了一个long型的数值, 如下所示:
void printLong(){
System.out.println(123456L);
}
那么在这个类的常量池中就会有一个CONSTANT_Long_info与之相对应, 这个CONSTANT_Long_info的形式如下:
代码反编译结果为:
Constant pool:
..............
..............#21 = Long 123456l
..............
..............{
..............
..............void printLong();
flags:
Code:
stack=3, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc2_w #21 // long 123456l
6: invokevirtual #23 // Method java/io/PrintStream.println:(J)V
9: return
LineNumberTable:
line 7: 0
line 8: 9
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/jg/zhang/TestInt;
}
6)CONSTANT_Double_info
一个常量池中的CONSTANT_Double_info数据项, 可以看做是CONSTANT_Double类型的一个实例。 它存储的是源文件中出现的double型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为6, 也就是说, 当虚拟机读到一个tag值为6的数据项时, 就知道这个数据项是一个CONSTANT_Double_info, 并且知道它存储的是double型数值。 紧挨着tag的下面8个字节叫做bytes, 就是double型的数值。 它的内存布局如下:
举例说明, 如果源文件中的一句代码使用了一个double型的数值, 如下所示:
void printDouble(){
System.out.println(123456D);
}
那么在这个类的常量池中就会有一个CONSTANT_Double_info与之相对应, 这个CONSTANT_Double_info的形式如下:
代码反编译结果为:
Constant pool:
..............
..............#21 = Double 123456.0d
..............
..............{
..............
..............void printDouble();
flags:
Code:
stack=3, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc2_w #21 // double 123456.0d
6: invokevirtual #23 // Method java/io/PrintStream.println:(D)V
9: return
LineNumberTable:
line 7: 0
line 8: 9
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/jg/zhang/TestInt;
}
7) CONSTANT_String_info
在常量池中, 一个CONSTANT_String_info数据项, 是CONSTANT_String类型的一个实例。 它的作用是存储文字字符串, 可以把他看做是一个存在于class文件中的字符串对象。 同样, 它的第一个字节是tag值, 值为8 , 也就是说, 虚拟机访问一个数据项时, 判断tag值为8 , 就说明访问的数据项是一个CONSTANT_String_info 。 紧挨着tag的后两个字节是一个叫做string_index的常量池引用, 它指向一个CONSTANT_Utf8_info, 这个CONSTANT_Utf8_info存放的才是字符串的字面量。 它的内存布局如下:
举例说明, 如果源文件中的一句代码使用了一个字符串常量, 如下所示:
void printStrng(){
System.out.println("abcdef");
}
那么在这个类的常量池中就会有一个CONSTANT_String_info与之相对应, 反编译结果如下:
Constant pool:
..............
..............
#21 = String #22 // abcdef
#22 = Utf8 abcdef..............
..............{
..............
..............void printStrng();
flags:
Code:
stack=2, locals=1, args_size=1
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #21 // String abcdef
5: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 7: 0
line 8: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/jg/zhang/TestInt;
}
其中printString方法中索引为3的字节码指令ldc引用常量池中的第21项, 第21项是一个 CONSTANT_String_info, 这个位于第21项的CONSTANT_String_info又引用了常量池的第22项, 第22项是一个CONSTANT_Utf8_info, 这个CONSTANT_Utf8_info中存储的字符串是 abcdef 。 引用关系的内存布局如下:
总结
本文主要讲解了常量池中的五中数据项, 分别为CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info, CONSTANT_Double_info 和CONSTANT_String_info 。
这几种常量池数据项都是直接存储的常量值,而不是符号引用。 这里又一次出现了符号引用的概念, 从本文中我们还可以知道。 虽然说CONSTANT_String_info是直接存储值的数据项, 但是CONSTANT_String_info有点特别, 因为它不是直接存储字符串, 而是引用了一个CONSTANT_Utf8_info, 这个被引用的CONSTANT_Utf8_info中存储了字符串。
原文链接:https://blog.csdn.net/zhangjg_blog/article/details/21658415