Java Compiler replacing StringBuilder with + concatenation

ぐ巨炮叔叔 提交于 2021-02-18 13:39:51

问题


Here's some simple Java code:

String s = new StringBuilder().append("a").append("b").append("c").toString();

I compile it with JRE 1.6, and I observe the following in the decompiled class file:

String s = "a" + "b" + "c";

I had the following questions:

  1. Why does the compiler choose '+' over StringBuilder?
  2. Do we have any official Java specification that justifies this behavior?
  3. Does it really make sense to use StringBuilder in such cases, where we know compiler is going to change it anyway?

回答1:


It's the other way round. + for String is implemented using StringBuilder (or StringBuffer) behind the scenes (see http://docs.oracle.com/javase/7/docs/api/java/lang/String.html or http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1).

Thus, once they're compiled, your two code snippets are indistinguishable. The decompiler has to make a guess at the original form.




回答2:


  1. The decompiler must have assumed that the bytecode instructions to call append over and over resulted from source code that used the + operator.

  2. Section 15.18.1 of the JLS specifies that a compiler can use a StringBuffer or similar means to implement the + operator between Strings:

    An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

    The StringBuilder class is a "similar technique".

  3. In this case, you can use either technique to concatenate your strings. If you have lots of complicated operations yielding strings that need to be concatenated, then you would be better off using a StringBuilder and appending them yourself.




回答3:


I am not sure about JDK 1.6 (javac is part of JDK) but when I compile it with JDK 1.7, I get an appropriate disassembly.

The compilers are smart. In JDK, I think if you have s = "a" + "b" + "c" it will perhaps do it this way (use StringBuilder instead), but not the other way. More concretely, if all strings are compile-time constants (string literals) it will do even better -- calculate the string literal and replace the concatenation with that, so there will be less overhead at runtime.




回答4:


Just For Reference

Your questions have already been answered by Oliver Charlesworth but I think you are checking the wrong place to start this question.

You should check the ByteCode using javap -v YouClass.class instead of using the IDE to check the decompiled code which can be quite confusing.

The original java code

public class LockElimination {
    private static String concat(String s1, String s2, String s3) {
        return s1 + s2 + s3;
    }
}

The ByteCode generated by 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;


来源:https://stackoverflow.com/questions/26048633/java-compiler-replacing-stringbuilder-with-concatenation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!