在Java中连接字符串是否总是导致在内存中创建新字符串?

我有一根长绳子,不适合屏幕的宽度。例如。

String longString = "This string is very long. It does not fit the width of the screen. So you have to scroll horizontally to read the whole string. This is very inconvenient indeed.";

为了便于阅读,我想过这样写——

String longString = "This string is very long." + 
                    "It does not fit the width of the screen." +
                    "So you have to scroll horizontally" +
                    "to read the whole string." +
                    "This is very inconvenient indeed.";

但是,我意识到第二种方法使用字符串串联,并将在内存中创建5个新字符串,这可能会导致性能下降。事实果真如此吗?或者编译器会足够聪明,弄清楚我所需要的只是一个字符串吗?我怎么能避免这样做?


答案 1

我意识到第二种方法使用字符串串联,并将在内存中创建5个新字符串,这可能会导致性能下降。

不,它不会。由于这些是字符串文本,因此将在编译时计算它们,并且只会创建一个字符串。这在 Java 语言规范 #3.10.5 中定义:

长字符串文本始终可以分解为较短的片段,并使用字符串串联运算符 +
[...]
此外,字符串文本始终引用类 String 的同一实例。

  • 由常量表达式 (§15.28) 计算的字符串在编译时计算,然后被视为文本。
  • 在运行时通过串联计算的字符串是新创建的,因此是不同的。

测试:

public static void main(String[] args) throws Exception {
    String longString = "This string is very long.";
    String other = "This string" + " is " + "very long.";

    System.out.println(longString == other); //prints true
}

但是,下面的情况有所不同,因为它使用变量 - 现在有一个串联并创建了几个字符串:

public static void main(String[] args) throws Exception {
    String longString = "This string is very long.";
    String is = " is ";
    String other = "This string" + is + "very long.";

    System.out.println(longString == other); //prints false
}

答案 2

在Java中连接字符串是否总是导致在内存中创建新字符串?

不,它并不总是这样做。

如果串联是编译时常量表达式,则由编译器执行,并将生成的 String 添加到已编译类常量池中。在运行时,表达式的值是与常量池条目对应的暂存值。String

这将在您的问题的示例中发生。