1. 字符串是什么?
-
字符串就是一段文字,比如
"Hello"
或者"你好"
。 -
在 Java 中,字符串是用
String
类型表示的。
2. 字符串的存储位置
-
字符串在内存中的存储分为两个地方:
-
字符串常量池:
-
这是一个"共享区域",专门用来存放那些直接用双引号写的字符串,比如
"Hello"
。 -
如果两个字符串的内容相同,它们会共享同一个内存空间,这样可以节省内存。
-
例如:
java
String s1 = "Hello"; // "Hello" 被放入常量池 String s2 = "Hello"; // s2 会复用常量池中的 "Hello"
这里
s1
和s2
指向的是同一个"Hello"
,所以s1 == s2
是true
。
-
-
堆内存:
-
如果你用
new
关键字创建字符串,比如new String("Hello")
,那么这个字符串会放在堆内存中。 -
堆内存中的字符串是独立的,即使内容相同,它们也是不同的对象。
-
例如:
java
String s3 = new String("Hello"); // 在堆内存中创建一个新的 "Hello"
这里
s3
是一个全新的对象,即使内容和s1
相同,s1 == s3
也是false
。
-
-
3. 字符串的不可变性
-
字符串一旦创建,它的内容就不能被修改。
-
比如:
java
String s = "Hello"; s = s + " World"; // 这里并不是修改 "Hello",而是创建了一个新的字符串 "Hello World"
- 原来的
"Hello"
还在内存中,新的"Hello World"
是一个全新的字符串。
- 原来的
4. 为什么要用字符串常量池?
-
节省内存:
- 如果有很多相同的字符串,比如
"Hello"
,它们可以共享同一个内存空间,而不是每个都单独存一份。
- 如果有很多相同的字符串,比如
-
提高性能:
- 因为字符串是不可变的,共享内存可以减少对象的创建和销毁,从而提高程序的运行效率。
5. intern()
方法的作用
-
如果你有一个字符串是在堆内存中创建的(比如用
new
),但你想把它放到字符串常量池里,可以用intern()
方法。 -
例如:
java
String s1 = new String("Hello"); // 在堆内存中创建 String s2 = s1.intern(); // 把 "Hello" 放入常量池(如果池中没有) String s3 = "Hello"; // 复用常量池中的 "Hello" System.out.println(s1 == s2); // false,因为 s1 在堆内存,s2 在常量池 System.out.println(s2 == s3); // true,因为 s2 和 s3 都指向常量池中的 "Hello"
6. 举个例子
假设你写了以下代码:
java
String s1 = "Hello"; // "Hello" 被放入常量池
String s2 = "Hello"; // s2 复用常量池中的 "Hello"
String s3 = new String("Hello"); // 在堆内存中创建一个新的 "Hello"
String s4 = s3.intern(); // 把 s3 的内容放入常量池(如果不存在)
内存中的情况是这样的:
-
字符串常量池:
+-------------------+ | "Hello" | <--- s1, s2, s4 +-------------------+
-
堆内存:
+-------------------+ | "Hello" | <--- s3 +-------------------+
7. 总结
-
字符串常量池:用来存放直接用双引号写的字符串,相同内容的字符串会共享内存。
-
堆内存 :用来存放用
new
创建的字符串,每个字符串都是独立的对象。 -
不可变性:字符串一旦创建,内容就不能修改,修改操作会创建新对象。
-
intern()
方法:可以把堆内存中的字符串放到常量池里。