【问题标题】:Java string concat in stringbuilder callstringbuilder调用中的Java字符串concat
【发布时间】:2011-12-01 13:43:13
【问题描述】:

据我所知,StringBuilder 通过在 concats 期间不在字符串池中创建临时字符串实例来帮助减少内存使用。 但是,如果我这样做会发生什么:

StringBuilder sb = new StringBuilder("bu");
sb.append("b"+"u");

是否编译成

sb.append("b");
sb.append("u");

?还是取决于优化标志?或者如果字符串生成器,我会失去全部好处? 还是这个问题没有意义? :)

【问题讨论】:

    标签: java string stringbuilder


    【解决方案1】:

    它编译为sb.append("bu"),因为编译器将多个字符串文字的串联转换为单个字符串文字。

    如果你有

    String a = "a";
    sb.append(a + "b");
    

    它会编译成

    String a = "a";
    String temp = a + "b"; // useless creation of a string here
    sb.append(temp);
    

    所以你应该更喜欢

    sb.append(a);
    sb.append("b");
    

    在这种情况下。

    【讨论】:

    • 这对 Java 来说是不是比较新?我一直被引导相信字符串连接会导致多个字符串,因为它们是不可变的?还是仅在连接字符串变量时才适用?
    • 不,这不是新的。能够正确格式化(在几行上)长字符串文字非常有用,例如长 SQL 或 JPQL 查询。
    • 对于第二个代码示例,不仅会创建一个 String,还会创建一个额外的 StringBuilder。
    • @JBNizet:给定String cd = "cd";,下面的字符串如何得到优化? String abcdef = "a" + "b" + cd + "e" + "f";??谢谢!
    【解决方案2】:

    不,"b" + "u" 将创建一个不可变的b 字符串,一个不可变的u 字符串,然后创建第三个不可变的bu 字符串,该字符串将被传递到StringBuilder 实例中。

    【讨论】:

    • 不,不会的。请参阅@aioobe 的回答。
    • 我不敢相信编译器不够聪明,不能创建单字母文字,或者,如果没有那么多否定,我相信编译器足够聪明,只能创建 bu 字符串。
    • @CarlosHeuberger - 这不是“聪明”。这只是实现 Java 语言规范的问题。
    • @Stephen - 被解读为:开发和实现编译器的人足够聪明......
    • @CarlosHeuberger - 阅读和实施规范是您对智能的定义吗?不过公平地说,规范很有可能反映了第一个编译器,而不是相反。
    【解决方案3】:

    错误:

    StringBuilder sb = new StringBuilder();
    sb.append("b"+"u");
    

    正确:

    StringBuilder sb = new StringBuilder();
    sb.append("b").append("u");
    

    BEST: //因为你已经知道里面会发生什么了! ;)

    StringBuilder sb = new StringBuilder();
    sb.append("bu");
    

    :)

    编辑

    我猜我上面的答案在只处理文字时是不正确的......

    :/

    【讨论】:

    • 其实,“WRONG”版本相当于“BEST”版本。请参阅@aioobe 的回答。
    • @StephenC:你知道编译器如何/如果/为什么优化以下内容:`String abcde = "a" + "b" + c + "d" + "e";?
    • @Gevorg - 我知道它确实如此,因为 JLS 说它确实如此,如果编译器不这样做,那么它就不是一个有效的 Java 编译器。
    【解决方案4】:

    由于"b" + "u" 是一个在编译时求值的表达式,它会被编译,就像你有"bu" 一样。

     0: new #2; //class StringBuilder
     3: dup
     4: ldc #3; //String bu
     6: invokespecial   #4; //Method StringBuilder."<init>":(String;)V
     9: astore_1
    10: aload_1
    11: ldc #3; //String bu
    13: invokevirtual   #5; // StringBuilder.append:(String;)LStringBuilder;
    

    另一方面,如果您有两个字符串变量,则此优化不会生效:

    下面的sn-p...

    StringBuilder sb = new StringBuilder("bu");
    String b = "b", u = "u";
    
    sb.append(b + u);
    

    ...编译为:

    0:  new #2; //class StringBuilder
    3:  dup
    4:  ldc #3; //String bu
    6:  invokespecial   #4; //Method StringBuilder."<init>":(String;)V
    9:  astore_1
    10: ldc #5; //String b
    12: astore_2
    13: ldc #6; //String u
    15: astore_3
    16: aload_1
    17: new #2; //class StringBuilder
    20: dup
    21: invokespecial   #7; //Method StringBuilder."<init>":()V
    24: aload_2
    25: invokevirtual   #8; //Method StringBuilder.append:(String;)StringBuilder;
    28: aload_3
    29: invokevirtual   #8; //Method StringBuilder.append:(String;)StringBuilder;
    32: invokevirtual   #9; //Method StringBuilder.toString:()String;
    35: invokevirtual   #8; //Method StringBuilder.append:(String;)StringBuilder;
    

    即类似于

    StringBuilder sb = new StringBuilder("bu");
    String b = "b", u = "u";
    
    StringBuilder temp = new StringBuilder();
    temp.append(b);
    temp.append(b);
    String result = temp.toString();
    
    sb.append(result);
    

    正如您在第 17-21 行中看到的那样,创建了一个额外的 StringBuilder 用于连接 ab。然后在第 32 行获取此临时 StringBuilder 的结果 String,并在第 35 行附加到原始 StringBuilder


    (字节码是由JDK中的javap命令生成的。试试看,真的很简单!)

    【讨论】:

    • 你猜对了我真正想问的 :) 所以当我只有文字时,优化就会发生,如果是变量,总是使用 append。
    • @aioobe:给定String cd = "cd";,以下两个是否也等价? String abcdef = "a" + "b" + cd + "e" + "f"; &lt;==&gt;String abcdef = "ab" + cd + "ef";`?谢谢!
    • @Gevorg,我相信是这样,你为什么不试试javap? :-)
    • 哈哈,不是。只需执行javac Test.java,然后执行javap -c Test
    • @aioobe:我做到了,太棒了! :) 它编译为"ab" + cd + "e" + "f"; 我也尝试了不同的输入,基本上只有变量之前的文字得到优化。非常有趣..我猜这可能与'+'的自然顺序有关..
    猜你喜欢
    • 2011-12-10
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 2019-03-09
    • 2010-12-04
    相关资源
    最近更新 更多