将String作为变量连接到Character vs与其他String连接时有什么区别?

JBA*_*JBA 22 java string performance operator-keyword

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

str1 + "a" + str2
Run Code Online (Sandbox Code Playgroud)

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

str1 + 'a' + str2
Run Code Online (Sandbox Code Playgroud)

更新:更好的例子(由@QPaysTaxes提供)以减少关于我原始示例的混淆.

我尝试了什么: 过去10年编程Java的各种东西,但我从来没有真正看到底层的东西 - 例如我会假设第二个稍微"更快/更好",因为没有为其创建的String-Object Java的斜杠标志和/或垃圾收集器必须处理更少.我曾经为Java证书做好准备,可能本来可以在那个时候更好地争论,但是我的日常业务似乎也是关于Java的"理论"必须保持最新...我知道没有任何比我indexOf('c')应该使用的假设更好的解释而不是indexOf("C")我想知道是否相同的字符串连接.

我也搜索了一下,但由于我的标题可能暗示我不太好描述我正在寻找的没有例子.对此我很抱歉,这个差点的可能性只是产生了重复.

我将尝试: 基于这里接受的答案字符串连接:concat()vs"+"运算符我希望能够有一个开始看到底层的什么,有一天能够争论/回答这样的问题,深入了解.

Jea*_*ard 16

基于这里接受的答案,我希望能够开始看到引擎盖下的内容.

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

String str1 = "a" + "test";
String str2 = 'a' + "test";
Run Code Online (Sandbox Code Playgroud)
0: ldc           #2                  // String atest
2: astore_1
3: ldc           #2                  // String atest
5: astore_2
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,没有区别,编译器会将其转换为相同的字节码.

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

String str1 = "a" + str3; //str3 is a String
String str2 = 'a' + str3; 
Run Code Online (Sandbox Code Playgroud)
 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;
Run Code Online (Sandbox Code Playgroud)

如你所见,有一点不同.

10: ldc           #5                  // String a
Run Code Online (Sandbox Code Playgroud)

ldc 将常量池(String,int或float)中的常量#index推入堆栈.

因此,如果您直接与变量连接,连接一个字符将生成更少的字节码,这就是幕后的内容.

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


Mar*_*tin 13

我更愿意使用"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
}
Run Code Online (Sandbox Code Playgroud)

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

Object arg = '/' + i;
Run Code Online (Sandbox Code Playgroud)

然后arg将只包含一个数字,因为char + int不连接,但添加值.


Axe*_*xel 5

如果你构造一个文件名,你肯定会在之后使用它.在大多数情况下,这涉及访问物理媒体,这种情况比连接字符串的任何错误都要慢.因此,做什么是可维护的,不要担心在这种特殊情况下的性能.

构建文件名时我的建议是使用File该类,或者Path自动确保路径分隔符正确.

编辑:正如您在评论中指出的那样,您的问题与一般情况有关.只要看看来源.StringBuilder.append(String)最终做System.arraycopy()String.getChars(),而StringBuilder.append(char)直接拷贝单个字符.所以从理论上讲,StringBuilder.append(char)会更快.

但是,您必须对此进行基准测试,以确定它在实践中是否有任何不同.