Java中字符串常量的连接

6

在C++中,我所知道的创建多行字符串的最佳方式是创建相邻的字符串,并让编译器在编译时将它们连接起来,就像这样:

string s = "This is a very long string ...\n"
   " and it keeps on going...";

在Java中,我所知道的唯一方法是使用字符串拼接:
String s = "This is a very long string ...\n" +
   " and it keeps on going...";

问题是,这是否在运行时生成单个字符串,还是Java在编译时实际上也进行了拼接?之所以会出现这个问题,是因为以下行为:
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); // this prints true, because the compiler
// generates only one "abc" object
String s3 = "a";
s3 += "bc";
System.out.println(s1 == s3); // false

1
是的,它可以。尝试使用static final修饰符将您的String设置为常量,然后s1 == s3将为真。编辑:哦,您甚至不需要这样做... - Bubletan
哎呀!我要编辑一下!好的,如果在不同的语句中编译器不会进行优化,这就是我向学生展示s1 != s3的方法。但是在单个语句中,它会被优化。 - Dov
1
哦,别开玩笑了。s1==s3true - Sid Zhang
1
看起来非常类似于https://dev59.com/hG_Xa4cB1Zd3GeqP37Bq,我认为它提供了您正在寻找的有用信息。 - Erik Gillespie
2个回答

3
String s3 = "a";
s3 += "bc";

与之相同:

String s3 = "a";
s3 = new StringBuilder().append(s3).append("bc").toString();

因此,它创建了一个新的String实例。

您甚至可以尝试:

String s = null;
s += null;
System.out.println(s); // prints "nullnull"

1
Java为每个字符串创建一个不可变的对象,但会重用字面量以获得性能提升。
这行代码创建了一个不可变的字符串。
String s1 = "abc"; 

由于这是一个字面量并且可以被编译器进行优化,因此将引用与s1相同的字符串字面量。

String s2 = "abc"; 

这是一个身份比较,你正在询问S1和S2是否是同一个对象,而不是相同的字符串。由于编译器通过使两个对象引用相同的不可变字符串进行优化,因此返回true。

System.out.println(s1 == s2);  

这段代码创建了两个不可变字符串,然后在运行时创建了第三个字符串。由于运行时无法保证能够有效地找到已经存在的字符串进行引用,因此它只能创建一个新对象并创建一个新的不可变字符串s3
String s3 = "a";
s3 = s3 + "bc";  

这是错误的,因为它们是两个不同的数据对象。
 System.out.println(s1 == s3); 

注意,字符串相等性返回true,以下是如何比较字符串对象的内容而不是对象位置。也就是说,第一次比较检查身份,第二次比较检查相等性。
 System.out.println(s1.equals(s3));

Java知道为每个字符串拼接步骤创建一个Data对象非常低效。为了帮助Java,有StringBuilder API可以做更有效的拼接。
 String s = "a";
 s += "b";
 s += "c";
 s += "d";
 s += "e";

在内存中创建并写入了'9'个字符串对象的结果...
 ("a", "b", "ab", "c", "abc", "d", "abcd", "e", "abcde")

字符串生成器有助于。
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");
sb.append("e");

使用单个连接更有效率,可以更好地利用内存。

("a", "b", "c", "d", "e", "abcde")

小细节: s1== s2 不是对象比较,而是对象的 引用 比较。它检查指向对象的引用的相等性,而不是对象本身。 - Ryan J
如果你真的运行了你发布的代码,你会发现你的前提是不正确的。在你的情况下,s1确实等于s3 - JonK
你没有理解重点,s3等于s1是因为它在字面常量池中。 - Dov
在编译时,“a”+“bc”被连接起来。它不会创建两个不可变的字符串。 - JonK
@JonK 请查看小的编辑。这完全取决于编译器是否进行了优化。 - gbtimmon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接