在第一个示例中,您将得到三个String
对象。您实际上可以在字节码中看到这一点。
假设您有以下代码:
public class StrTest {
public static void main(String[] args) {
String str1 = "JAVA";
String str2 = "WORLD";
String str3 = str1 + str2;
String strTest = "JAVA" + "WORLD";
}
}
生成的字节码是:
public class StrTest {
public StrTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String JAVA
2: astore_1
3: ldc #3 // String WORLD
5: astore_2
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: ldc #8 // String JAVAWORLD
27: astore 4
29: return
}
您可以看到 Java 编译器在字符串池中创建了两个实例String
。要将这两个附加在一起,它创建了一个实例并附加了值。之后,它调用该实例,该实例在其中创建一个新实例。"JAVA"
"WORLD"
StringBuilder
toString()
String
"JAVAWORLD"
在第二种情况下,您只会得到一个String
实例,因为 Java 编译器足够聪明,可以看到您基本上拥有的是一个常量,因此它通过评估该表达式并在字符串中创建一个 String
实例来执行一些编译时优化包含"JAVAWORLD"
. 然后将该实例的引用分配给strTest
。
关于字符串"JAVA"
、"WORLD"
和"JAVAWORLD"
,这些基本上是实习字符串。由于字符串在 Java 中是不可变的,因此您只需要一个对唯一实例的引用,该实例可以在代码中的多个位置重用。这基本上是一种节省内存的方法。
所以总结一下:
- 案例1:三个
String
实例:池中的两个,追加后新构造的一个(StringBuilder
还创建了一个实例来追加两个字符串,总共有4个对象)。
- 案例 2:池中的一个实例。