Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java编译器将StringBuilder替换为+;串联_Java_Stringbuilder_Compiler Optimization - Fatal编程技术网

Java编译器将StringBuilder替换为+;串联

Java编译器将StringBuilder替换为+;串联,java,stringbuilder,compiler-optimization,Java,Stringbuilder,Compiler Optimization,下面是一些简单的Java代码: String s = new StringBuilder().append("a").append("b").append("c").toString(); 我使用JRE 1.6编译它,在反编译的类文件中观察到以下内容: String s = "a" + "b" + "c"; 我有以下问题: 为什么编译器选择“+”而不是StringBuilder 我们是否有任何正式的Java规范来证明这种行为 在这种情况下使用StringBuilder真的有意义吗?我们知道编

下面是一些简单的Java代码:

String s = new StringBuilder().append("a").append("b").append("c").toString();
我使用JRE 1.6编译它,在反编译的类文件中观察到以下内容:

String s = "a" + "b" + "c";
我有以下问题:

  • 为什么编译器选择“+”而不是StringBuilder
  • 我们是否有任何正式的Java规范来证明这种行为
  • 在这种情况下使用StringBuilder真的有意义吗?我们知道编译器无论如何都会更改它

  • 相反<
    String
    的代码>+在后台使用
    StringBuilder
    (或
    StringBuffer
    )实现(请参阅或)

    因此,一旦编译完成,您的两个代码片段就无法区分。反编译器必须猜测原始形式

  • 反编译器必须假设要反复调用
    append
    的字节码指令来自使用
    +
    运算符的源代码

  • 指定编译器可以使用
    StringBuffer
    或类似方法在
    String
    s之间实现
    +
    运算符:

    实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间字符串对象。为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类或类似技术来减少通过表达式求值创建的中间字符串对象的数量

    StringBuilder
    类是一种“类似的技术”

  • 在这种情况下,您可以使用这两种技术连接字符串。如果有许多复杂的操作产生需要连接的字符串,那么最好使用
    StringBuilder
    并自己附加它们


  • 我不确定JDK1.6(javac是JDK的一部分),但当我用JDK1.7编译它时,我得到了一个合适的答案

    编译器很聪明。在JDK中,我认为如果有s=“a”+“b”+“c”,它可能会这样做(改用StringBuilder),但不是相反。更具体地说,如果所有字符串都是编译时常量(字符串文字),它会做得更好——计算字符串文字并用它替换连接,这样运行时的开销就会更少。

    仅供参考

    Oliver Charlesworth已经回答了您的问题,但我认为您在开始这个问题时选择了错误的位置

    您应该使用
    javap-vyouclass.class
    检查字节码,而不是使用IDE检查反编译的代码,因为反编译的代码可能会非常混乱

    原始java代码

    public class LockElimination {
        private static String concat(String s1, String s2, String s3) {
            return s1 + s2 + s3;
        }
    }
    
    javap-v LockElimination.class生成的字节码

    Constant pool:
       #1 = Methodref          #7.#16         // java/lang/Object."<init>":()V
       #2 = Class              #17            // java/lang/StringBuilder
       #3 = Methodref          #2.#16         // java/lang/StringBuilder."<init>":()V
       #4 = Methodref          #2.#18         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       #5 = Methodref          #2.#19         // java/lang/StringBuilder.toString:()Ljava/lang/String;
    
    常量池:
    #1=Methodref#7.#16//java/lang/Object.“:()V
    #2=类#17//java/lang/StringBuilder
    #3=Methodref#2.#16//java/lang/StringBuilder。”“:()V
    #4=Methodref#2.#18//java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    #5=Methodref#2.#19//java/lang/StringBuilder.toString:()Ljava/lang/String;
    
    你确定你已经反编译了类的正确版本吗?你看到的是反编译器试图变得聪明,而不是编译后的代码的实际外观。
    StringBuilder
    对于常量字符串没有意义。如果我写
    字符串s=“a”+“b”+“c”编译器使用
    javap-c
    生成如下所示的行:
    0:ldc#2//String abc
    。因此,它是智能的,常量字符串被“粘合”成一个字符串。这意味着我们可以“免费”使用+进行代码格式化,这一点非常重要。