字符串常量池
约 855 字大约 3 分钟
2025-09-04
在 Java 中,字符串是不可变的(immutable),这意味着一旦创建了一个 String 对象,其内容就不能被修改。为了优化性能和减少内存消耗,Java 引入了字符串常量池(String Pool)的概念。
字符串常量池是堆内存中的一个特殊区域,用于存储字符串字面量(String Literal)和通过 String.intern() 方法明确添加到池中的字符串。
字符串常量池的工作原理
当程序中通过以下方式创建字符串时:
字符串字面量:例如
String s = "Hello";当 Java 虚拟机(JVM)执行到字符串字面量时,它会首先检查字符串常量池中是否已经存在一个内容相同的字符串对象。- 如果存在,JVM 会直接返回该池中字符串对象的引用。
- 如果不存在,JVM 会在池中创建一个新的字符串对象,并将该对象的引用返回。
new String()构造器:例如String s = new String("Hello");使用new String()构造器时,JVM 会在堆内存中创建一个新的String对象,即使字符串常量池中已经存在相同内容的字符串。如果构造器参数是字符串字面量,那么这个字面量本身也会触发在字符串常量池中创建或查找字符串对象。
String.intern() 方法
String.intern() 是一个原生方法,其作用是将当前字符串对象尝试放入字符串常量池。
- 如果字符串常量池中已经存在一个内容与当前字符串对象相同的字符串,那么
intern()方法会返回池中那个字符串对象的引用。 - 如果字符串常量池中不存在内容与当前字符串对象相同的字符串,那么会根据 Java 版本的不同有不同的行为:
- JDK 1.6 及之前:会将当前字符串对象的内容复制一份,然后在字符串常量池中创建一个新的
String对象,并返回该新对象的引用。 - JDK 1.7 及之后:如果字符串常量池中不存在,则会将当前字符串对象的引用直接放入字符串常量池,并返回该引用。
- JDK 1.6 及之前:会将当前字符串对象的内容复制一份,然后在字符串常量池中创建一个新的
以下代码演示了字符串常量池的行为:
public class StringPoolExample {
public static void main(String[] args) {
// s1 和 s2 都通过字符串字面量创建
// "Hello" 首次出现时,会在字符串常量池中创建
String s1 = "Hello";
// s2 会直接引用池中已存在的 "Hello" 对象
String s2 = "Hello";
// s3 通过 new String() 创建,会在堆内存中创建一个新的 String 对象
// 同时,"Hello" 字面量会确保在字符串常量池中存在
String s3 = new String("Hello");
// s4 通过 new String("Hello").intern() 创建
// new String("Hello") 仍然会在堆中创建一个新对象
// .intern() 方法会检查字符串常量池,由于 "Hello" 已在池中,s4 将引用池中的 "Hello" 对象
String s4 = new String("Hello").intern();
System.out.println("s1 == s2: " + (s1 == s2)); // true,都引用池中的 "Hello"
System.out.println("s1 == s3: " + (s1 == s3)); // false,s1 引用池中,s3 引用堆中新对象
System.out.println("s1 == s4: " + (s1 == s4)); // true,s1 和 s4 都引用池中的 "Hello"
System.out.println("s3 == s4: " + (s3 == s4)); // false,s3 引用堆中新对象,s4 引用池中对象
}
}