将字符串作为变量与字符连接与与其他字符串连接时有什么区别?

2022-09-02 00:52:34

当我看到这样的东西(伪1行)时:

str1 + "a" + str2

它是否比以下(伪1线)差(或更好/相等)?

str1 + 'a' + str2

更新:更好的例子(通过@QPaysTaxes)来减少对我的原始示例的混淆。

我尝试了什么:在过去的10年里,我编程Java的各种东西,但我从未设法真正看到引擎盖下的东西 - 例如,我会假设第二个稍微“更快/更好”,因为没有为斜杠符号创建的String-Object(s)和/或Java的垃圾收集器必须处理更少。我曾经为Java证书做准备,并且可能能够在那个时候更好地争论,但似乎即使如此,关于Java的“理论”也必须保持最新状态......我知道没有任何比我的假设更好的解释应该使用而不是,我想知道字符串串联是否也算作相同的解释。indexOf('c')indexOf("C")

我也用谷歌搜索了一下,但由于我的标题可能暗示我不太好在没有例子的情况下描述我正在寻找的东西。我很抱歉,这个让分盘只是产生了一个重复。

我将尝试什么:基于这里接受的答案 字符串串联:concat() vs “+” 运算符 我希望能够开始看到引擎盖下的内容,并且有一天能够争论/回答这些深刻的问题。


答案 1

基于这里公认的答案,我希望能够开始看看引擎盖下的东西。

让我们看一下将字符串与字符连接时生成的字节码:

String str1 = "a" + "test";
String str2 = 'a' + "test";

0: ldc           #2                  // String atest
2: astore_1
3: ldc           #2                  // String atest
5: astore_2

如您所见,没有区别,编译器会将其转换为相同的字节码。

现在,让我们看一下将字符连接到 String 变量时生成的字节码。

String str1 = "a" + str3; //str3 is a String
String str2 = 'a' + str3; 

 7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
10: ldc           #5                  // String a
12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: new           #3                  // class java/lang/StringBuilder
26: dup
27: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
30: bipush        97
32: invokevirtual #8                  // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
35: aload_1
36: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

如您所见,有一点不同。

10: ldc           #5                  // String a

ldc将常量#index从常量池(字符串、整型或浮点型)推送到堆栈上。

因此,如果您直接与变量连接,则连接字符将生成较少的字节码,这就是底层的内容

现在,对于性能问题,这不会代表任何显著的性能差异,因为 JIT 编译器优化了大多数临时对象,除非您在运行程序时指定使用 禁用 JIT 编译器。-Djava.compiler=NONE


答案 2

我更喜欢使用而不是确保结果是."a"'a'String

请考虑以下情况:

public static void main(String... args) {
    String s = "foo";
    int i = 1;
    Object arg = s + '/' + i;
    log(arg);
}

private static void log(Object... args) {
    MessageFormat format = new MessageFormat("bar {0}");
    String message = format.format(args);
    System.out.println(message); // or write to a log or something
}

假设您决定不再需要该消息,并将方法中的第三行更改为:smain

Object arg = '/' + i;

然后将只包含一个数字,因为不连接,而是将值相加。argchar + int