-
字符串字面量:
- 当使用字符串字面量(如
String s = "hello";
)时,JVM会首先检查字符串常量池中是否已经存在该字符串。 - 如果存在,则不会创建新对象,而是返回常量池中该字符串的引用。
- 如果不存在,则会在常量池中创建一个新的字符串对象,并返回其引用。
- 当使用字符串字面量(如
-
使用
new
关键字:- 使用
new String("hello")
时,无论常量池中是否存在"hello"
,都会在堆内存中创建一个新的String
对象。 - 这个新对象的内容与常量池中的
"hello"
相同,但它是一个全新的对象,有自己的内存地址。 - 常量池中的字符串不受影响。
- 使用
-
字符串拼接:
- 使用
+
操作符拼接字符串时,如果参与拼接的字符串都是常量且没有变量参与,编译器可能会进行优化,将结果作为单个字符串字面量放入常量池(这取决于编译器的实现和JVM的优化)。 - 如果拼接过程中涉及到了变量,那么结果通常是通过
StringBuilder
(或StringBuffer
)在堆内存中构建的,最终通过toString()
方法创建一个新的String
对象,这个对象不会被放入常量池。 +=
操作符主要用于字符串的拼接。当用于字符串时,它实际上是在内部通过StringBuilder
(或StringBuffer
,但在单线程环境下通常使用StringBuilder
以提高性能)来实现的。这意味着,每次使用+=
拼接字符串时,都会调用StringBuilder
的append()
方法来添加新的字符串部分,并在最终需要字符串结果时调用toString()
方法。
- 使用
-
使用
StringBuilder
或StringBuffer
:- 显式使用
StringBuilder
或StringBuffer
来构建字符串时,最终通过调用toString()
方法会创建一个新的String
对象。 - 这个新对象不会被自动放入常量池,除非后续显式地调用
intern()
方法。
- 显式使用
-
String.intern()
方法:intern()
方法用于确保当且仅当字符串常量池中不存在当前字符串时,才会将其添加到池中,并返回常量池中的字符串的引用。- 如果使用
new
创建的字符串对象调用intern()
,并且常量池中已经存在相同的字符串,那么intern()
会返回常量池中字符串的引用,而不是新创建对象的引用。
public static void main(String[] args) {
String s = "laowang";
String wang = "wang";
String s1 = new String("laowang");
String s2 = "lao" + "wang";
String s3 = "lao" + wang;
String s4 = "lao";
s4 += "wang";
StringBuilder sb = new StringBuilder();
sb.append("lao");
sb.append("wang");
String s5 = sb.toString();
String s6=s.intern();
System.out.println(s==s1);//s常量池中,s1堆内存中
System.out.println(s1==s2);//s2常量池
System.out.println(s==s2);//都是常量池中
System.out.println(s2==s3);//s3堆内存中
System.out.println(s1==s3);//堆中两个不同对象
System.out.println(s3==s4);//堆中两个不同对象
System.out.println(s4==s5);//堆中两个不同对象
System.out.println(s5==s6);//s6常量池中,s5堆内存中
System.out.println(s6==s);//常量池中
}
false
false
true
false
false
false
false
false
true