You really do understand String and StringBuilder

Foreword

The interview may often ask this question: Tell me about the difference between String, StringBuilder, StringBuffer, and many people may say that if the String by +the time (which is a good plus, followed by the same token) to concatenate strings, creates a lot of temporary variable, performance is relatively low (so many online posts also wrote), but really so?

String splicing

In fact, in order to know String through +time to splice the string, in the end there is no create temporary variables? In fact, this problem is very simple, just need to javapdecompile the generated class file to see if the class file String operations done on it. Here we are in the "java programming ideas" string section an example to explain.

First we look at the following code:

public class Test {
    public static void main(String[] args){
        String mango = "mango";
        String s = "abc" + mango + "def" + 47;
        System.out.println(s);
    }
}
复制代码

This code is more typical through +to the code string concatenation, by then we javac Test.javacompile this code, then javap -c Test.classdecompile the generated Test.classfiles. Weed out unrelated part, it shows the main()code bytecode, so with the following bytecode. You will find very interesting thing happened.

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: ldc           #2                  // String mango
         2: astore_1
         3: new           #3                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #5                  // String abc
        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: ldc           #7                  // String def
        21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        24: bipush        47
        26: invokevirtual #8                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        29: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        32: astore_2
        33: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
        36: aload_2
        37: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        40: return
}
复制代码

Here it comes to assembly language, readers can search online bytecode instruction list there will be many, I offer here a reader can look at the table to understand the meaning of each instruction, I am not here to expand in detail. After each instruction may be //, //the contents of the instruction code representing the objects behind operation. Careful readers will find: the compiler automatically introduces java.lang.StringBuilder (where the front of java Lis a reference type, you want to learn more about the reader can look at "in-depth understanding of the Java Virtual Machine" in the class file structure chapter) . Although we did not use StringBuilder in the source code, but the compiler has given a free hand to use it, because it is more efficient.

After watching the above bytecode you will find that the compiler creates a StringBuilder object, +each connected to a string using a number of append()methods to splice, a total of four calls, last call toString () method to generate results. (Note: if the interested reader can be used to replace the above code StringBuilder by javac javaprecompiling, then you will find main()generated in the process is the same bytecode).

in conclusion

By the above example we found that when we pass +a string to splice, the compiler will automatically optimize for us to splice into the StringBuilder, and will not cause the Internet said the creation of temporary variables, slow down these shortcomings. (Note: Since StringBuidler is introduced after jdk5.0, jdk5.0 before it is spliced to StringBuffer by the interested reader can then authenticate itself).

extend

Now, we will certainly be very happy, since compilers are optimized for us, that we are not free to use Stringof it (think of all happy). Haha, do not get too excited, because sometimes optimizing compiler may not be the results you want. Let's look at the following code:

The following program to generate a String in two ways: using a plurality of methods String object; two code method used StringBuidler.

public class Test {
    public String testString(String[] fields) {
        String result = "";
        for (int i = 0; i < fields.length; i++) {
            result += fields[i];
        }
        return result;
    }

    public String testStringBuilder(String[] fields){
        StringBuilder result = new StringBuilder();
        for (int i = 0; i<fields.length; i++){
            result.append(fields[i]);
        }
        return result.toString();
    }
}
复制代码

The above two methods perform similar code, are passed string array, then forloop stitching together the array of strings, a first difference method is used Stringto splice the second method used StringBuilderto splice. Then we pass javapto decompile the code, eliminate independent part, will see the bytecode two methods.

First, testString()the bytecode method:

public java.lang.String testString(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=4, args_size=2
         0: ldc           #2                  // String
         2: astore_2
         3: iconst_0
         4: istore_3
         5: iload_3
         6: aload_1
         7: arraylength
         8: if_icmpge     38
        11: new           #3                  // class java/lang/StringBuilder
        14: dup
        15: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        18: aload_2
        19: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        22: aload_1
        23: iload_3
        24: aaload
        25: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        28: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        31: astore_2
        32: iinc          3, 1
        35: goto          5
        38: aload_2
        39: areturn
复制代码

Here readers look at the line 8 if_icmpge, the control table is found bytecode instructions for the instruction loop is to compare ithe value equal to a certain time into the circulation, back out of the loop 38 represents the line 38, where the first loop 8row to 35row. It means line 35: return loop start point (first 5row). Then we see (the first loop 8line to the first 35line 11 lines), is a newcommand, this too familiar, is to create objects. But it is actually inside the loop, which means that each time through the loop, it is necessary to create a new StringBuilderobject. This is clearly unacceptable.

Then we look at what testStringBuilder()bytecode:

public java.lang.String testStringBuilder(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=4, args_size=2
         0: new           #3                  // class java/lang/StringBuilder
         3: dup
         4: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
         7: astore_2
         8: iconst_0
         9: istore_3
        10: iload_3
        11: aload_1
        12: arraylength
        13: if_icmpge     30
        16: aload_2
        17: aload_1
        18: iload_3
        19: aaload
        20: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        23: pop
        24: iinc          3, 1
        27: goto          10
        30: aload_2
        31: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        34: areturn
复制代码

We can see that the code is not only part of the body of the loop shorter, simpler, and it newis only the beginning of a call, indicating only generated a StringBuilder object.

Conclusions extension

So, when you write a class toString()when the method, if the string operation is relatively simple, it can rely on the compiler, it would be reasonable final result string configuration for you. But if you want to toString()use cyclic process, then you need to create a StringBuilder object. Of course, when you can not decide, then you can always analyze your program by javap.

Remain a problem: enumeration we should all know, but you know in the end is how it performed in the jvm it? (Thinking: in fact, want to know how it works is very simple, you can also write a enumeration code, and then by javapanti-compile the code, you will have a clear insight into the feeling.)

references

- "java programming ideas"

Guess you like

Origin juejin.im/post/5d161dc06fb9a07ec63b28be