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.