JDK版本:8
"常量池"有哪些
- class文件中的常量池
- 运行时常量池
- 字符串常量池
class文件的常量池
存储在磁盘上,class文件的Constant Pool,通过javap -verbose可以查看,静态的
运行时常量池
存储在instanceKlass实例(元空间),通过HSDB可以查看,动态的
字符串常量池(本文重点)
存储在虚拟机堆,StringTable(c++类,底层是HashTable),动态的
字符串常量池存储结构
字符串常量池底层是一个StringTable类型对象,StringTable是HashTable的子类,所以把它看作HashTable就很好理解了。
HashTable底层数据结构是数组+链表,数组的每个位置存放HashtableEntry链表,每个HashtableEntry对象存储key、value键值对,HashtableEntry存放在数组哪个位置由HashtableEntry的key值与数组长度取余来决定。
HashtableEntry的key是根据字符串内容+字符串内容的长度计算出来的hash值,value指向String对象。
String对象指向char数组,char数组保存实际数据。
String a = “aaa”;存储结构
需要明确的是:由于"aaa"是写死的,所以会进入字符串常量池。上文介绍字符串常量池存储结构时用的就是这个例子,所以不在赘述。
总结String a = “aaa”;这行代码会生成一个String对象,一个char数组。
String b = new String(“bbb”);存储结构
首先由于"bbb"是写死的,所以会进入字符串常量池。
String b = new String(“bbb”);这行代码会生成两个String对象,一个char数组,因为显示声明了一个String对象,所以比上个案例多一个String对象,两个String对象指向同一个char数组。
String c = “aaa” + “bbb”;存储结构
两个写死的字符串拼接,在编译期间就会进行优化,变成String c = “aaabbb”;,等同于第一个案例,会生成一个String对象,一个char数组。
String d = “aaa” + new String(“bbb”);存储结构
"aaa"和"bbb"是写死的会进入字符串常量池,"aaabbb"是计算出来的,所以不会进入字符串常量池。
这里需要注意的是new String(“bbb”),如果直接声明一个引用指向他,那会生成一个新的String对象;如果只是用于计算,则不会。所以String d = “aaa” + new String(“bbb”);这行代码会生成三个String对象,三个char数组。