数据结构中字符串存储的深度解析



目录
一、存储架构
1. 字符串常量池
2. 字符串哈希表
2.1 构造
2.2 基本存储单元
2.2.1 键对象
2.2.2 值对象
二、存储流程
1. 查找
2. 创建
三、存储所在之处
四、存储操作
1. 新建操作
2. 入池操作
一、存储架构
1. 字符串常量池
字符串常量池与字符串哈希表协同工作,用于存储所有由双引号包裹的字符串字面量。
2. 字符串哈希表
2.1 构造
字符串哈希表采用HashMap
的存储结构,通过开散列方式处理哈希冲突。
2.2 基本存储单元
哈希数组中的基本存储单元是链表节点,每个节点包含键对象、值对象以及冲突时的下一个节点引用,且每个链表节点都包含Map的包装节点:
- 键对象:由字符串字面量生成哈希值,哈希值经哈希函数计算后得到在哈希数组中的存储索引。不同字符字面量产生的哈希值通常不同,但哈希函数计算出的索引可能相同导致哈希冲突,故用链表将冲突的节点连接,存储在同一索引位置。
- 值对象:是管理该字符串的String类实例对象的引用。
二、存储流程
1. 查找
任何以双引号写出并存在的字符串字面量,都会访问字符串哈希表,根据其字符串字面量生成哈希值,经哈希函数计算得到索引,然后在该索引位置的链表中查找。通过节点存储的键值哈希值判断是否存在包含此字面量常量内容的节点。若找到该节点,则返回该节点值对象所引用的管理此字面量的String实例对象。
2. 创建
若查找后未发现对应哈希值的节点,说明常量池中尚未创建该字符串字面量常量,则需创建该字符串字面量及其存储管理结构:
1. 在常量池中创建此字面量内容的字符数组;
2. 创建管理该字符数组的String类实例对象:将value
属性设置为该字符数组的引用以管理此字面量字符数组,将hash
属性设置为此字符串字面量的哈希值;
3. 创建哈希表中相连的链表节点:键对象存储此字面量的哈希值,值对象存储该String类实例对象的引用并连接链表,next
指针设为null
;
4. 将此链表节点连接到哈希表中。
通过以上步骤,构建起从哈希表链表节点到字符串常量池字面量字符数组的访问管理路径。
三、存储所在之处
- 字符串常量池和字符串哈希表均存储于堆区。
char[] ChArray = new char[]{'a','b','c'}
,创建的字符数组存储在堆区中字符串常量池以外的部分。- 当执行
new String(ChArray)
时,会将外部分堆区的字符数组拷贝,再创一份存储在外堆并进行管理。
四、存储操作
1. 新建操作
String s = new String("hello");
new String("hello")
执行时,双引号写出的内容存在时,常量池中已创建此字面量字符数组、管理该常量池字符数组的String类实例对象以及哈希表中连接其String引用访问信息的链表节点。但new
操作会在堆中新建一个String类实例对象,该对象同样指向并管理此常量池的字面量字符数组。
2. 入池操作
s.intern();
s.intern()
从字符串哈希表出发检查此字符串的字面量在字符串常量池中是否存在。搜索链表后,若未发现对应哈希值的链表节点,说明常量池中不存在此字符串字面量,则在哈希表此位置创建节点连接该String实例对象,并将堆中的字符数组移至常量池,将堆中的字符数组纳入池中,构建成哈希表节点、String实例对象、字符串常量池字符数组一套管理的字符串字面量常量。