StringBuffer StringBuilder

String

First of all, String is used to represent a String constant. It is an immutable object, meaning that once we create a String, we cannot change its value. As we can see from its source code, it uses a final array to store its contents, meaning that it is a constant.

    /** The value is used for character storage. */
    private final char value[];Copy the code

Here’s an example:

public class Main {

    public static void main(String[] args) {

        String s1 = "a";
        String s2 = "a";
        String s3 = new String("a");
        System.out.println(s1 == s2); // true
        System.out.println(s1 == s3); // false

        String s4 = new String("b");
        String s5 = new String("b");
        System.out.println(s4 == s5); // false

        String s6 = "a" + "b";
        String s7 = "ab";
        System.out.println(s6 == s7); // true

        String s8 = new String("ab");
        System.out.println(s6 == s8); // false
        System.out.println(s7 == s8); //false
    }
}Copy the code

Because the String is stored in the constant pool, virtual opportunity to optimize, above, although the statement of eight variables, but only in the constant pool for the “a”, “b”, “ab”, the three constants using jclasslib view, as shown below:

Declare a string object. If it can be found in the constant pool, refer to it directly.

Since strings are immutable objects, what happens if multiple strings are added together?

        String s1 = "a" + "b" + "c" + "d" + "e";
        System.out.println(s1);Copy the code

Analyzing bytecode:

As you can see, the JVM still loads “abcde” into memory once, with only one string variable in the constant pool, “abcde”, as shown below:

The LDC directive loads a string into the constant pool (Push item from run-time)

That is, passing “A” + “b” + “c” + “d” + “e” and “abcde” are the same thing for the JVM and will only be loaded once;

But what happens when you add them up this way?

        String s1 = "a";
        String s2 = "b";
        String s3 = "c";
        String s4 = "d";
        String s5 = "e";
        String s6 = s1 + s2 + s3 + s4 + s5;
        System.out.println(s6);Copy the code

First, let’s see how many times the JVM calls the LDC instruction to load the string into the constant pool:

Let’s look at a complete bytecode in this way:

0 ldc #2 <a> 2 astore_1 3 ldc #3 <b> 5 astore_2 6 ldc #4 <c> 8 astore_3 9 ldc #5 <d> 11 astore 4 13 ldc #6 <e> 15 astore  5 17 new #7 <java/lang/StringBuilder> 20 dup 21 invokespecial #8 <java/lang/StringBuilder.<init>> 24 aload_1 25 invokevirtual #9 <java/lang/StringBuilder.append> 28 aload_2 29 invokevirtual #9 <java/lang/StringBuilder.append> 32 aload_3 33 invokevirtual #9 <java/lang/StringBuilder.append> 36 aload 4 38 invokevirtual #9 <java/lang/StringBuilder.append> 41 aload 5 43 invokevirtual #9 <java/lang/StringBuilder.append> 46 invokevirtual #10 <java/lang/StringBuilder.toString> 49 astore 6Copy the code

As you can see, the JVM optimizes the way strings are added by using StringBuilder to concatenate strings.

StringBuffer

A StringBuffer is a mutable string that holds elements ina char array that does not have a final modifier. The initial size of the char array is 16.

StringBuffer sb = new StringBuffer();
                |
                |
    public StringBuffer() {
        super(16);
    }
                |
                |
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
                |
                |
         char[] value;
       
Copy the code

Then use its append method to concatenate strings:

        String s1 = "a";
        String s2 = "b";
        String s3 = "c";
        String s4 = "d";
        String s5 = "e";

        StringBuffer sb = new StringBuffer();
        sb.append(s1).append(s2).append(s3).append(s4).append(s5);Copy the code

The bytecode is as follows:

0 ldc #2 <a> 2 astore_1 3 ldc #3 <b> 5 astore_2 6 ldc #4 <c> 8 astore_3 9 ldc #5 <d> 11 astore 4 13 ldc #6 <e> 15 astore  5 17 new #7 <java/lang/StringBuffer> 20 dup 21 invokespecial #8 <java/lang/StringBuffer.<init>> 24 astore 6 26 aload 6 28 aload_1 29 invokevirtual #9 <java/lang/StringBuffer.append> 32 aload_2 33 invokevirtual #9 <java/lang/StringBuffer.append> 36 aload_3 37 invokevirtual #9 <java/lang/StringBuffer.append> 40 aload 4 42 invokevirtual #9 <java/lang/StringBuffer.append> 45 aload 5 47 invokevirtual #9 <java/lang/StringBuffer.append> 50 pop 51 returnCopy the code

In addition, StringBuffer is thread-safe and can be used with multiple threads, and the append method is modified by synchronized to ensure synchronization:

    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }Copy the code

StringBuilder

A StringBuilder, like a StringBuffer, is a mutable string. The char array used to hold elements is not final and has an initial size of 16.

StringBuilder sb = new StringBuilder();
               |
               |
    public StringBuilder() {
        super(16);
    }
               |
               |
 AbstractStringBuilder(int capacity) {
        value = new char[capacity];
 }
               |
               |
          char[] value;
Copy the code

StringBuilder and StringBuffer have a common parent class:

However, StringBuilder is not thread-safe, and data inconsistencies can occur when used in multithreaded environments. Its append method does not use the synchronized modifier:

    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }Copy the code

It concatenates the bytecode of the string through append just as StringBuffer does.

conclusion

In conclusion,

String is an immutable object that does not change once it is created, and the JVM calls the StringBuilder append for optimization.

StringBuffer is a mutable string, it’s thread-safe.

StringBuilder is also a mutable string, but it is not thread-safe, and it shares a parent class with StringBuffer.

Because the Append method of A StringBuffer is modified by synchronized, its performance is lower than that of a StringBuilder, which can be used in a single thread.