Coding With Fun
Home Docker Django Node.js Articles FAQ

Java interview question: Talk about the difference between String, StringBuffer, StringBuilder?


May 31, 2021 Article blog


Table of contents


The article comes from the public number: Program New Horizons Author: Ugly Fat Man Ii Brother

Interview questions about strings, in addition to memory distribution equals are most commonly distinguished from StringBuffer and StringBuilder

If you answer: String classes are immutable, StringBuffer and StringBuilder are variable classes, StringBuffer is thread-safe, StringBuilder is not thread-safe.

As far as the above summary is concerned, there seems to be a little less to know. This article takes you through a comprehensive look at the differences between the three of them and the underlying implementations.

The stitching of string strings

As detailed in previous articles on String strings, its immutability is also caused by the generation of new strings in memory whenever a "plus" operation is passed.

String a = "hello ";
String b = "world!";
String ab = a + b;

For the above code, the memory distribution is as follows:

 Java interview question: Talk about the difference between String, StringBuffer, StringBuilder?1

Where a and b are initialized in the string constant pool, the ab-stitched objects are in the heap. I t's intuitive to see that after stitching up the new generation String a String object. If you stitch multiple times, more than one intermediate object is generated.

The above conclusion was established prior to Java8 when JDK optimized the stitching of the "plus" number, and the stitching described above was optimized for processing by Java8 StringBuilder append methods.

stack=2, locals=4, args_size=1
     0: ldc           #2                  // String hello
     2: astore_1
     3: ldc           #3                  // String world!
     5: astore_2
     6: new           #4                  // class java/lang/StringBuilder
     9: dup
    10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
    13: aload_1
    14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    17: aload_2
    18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    21: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    24: astore_3
    25: return

Above, the result of the bytecode is decompiled by the java p -verbose command, and it is clear that the creation of StringBuilder and the call to the 'append method' can be seen.

At this point, it would be wrong to add a general answer that multiple String objects are created by stitching strings with plus signs, so performance is worse than StringBuilder Because essentially the effect of plus-size stitching is eventually processed by the compiler and is consistent with StringBuilder

If you use the following in your code:

StringBuilder sb = new StringBuilder("hello ");
sb.append("world!");
System.out.println(sb.toString());

The compiler's plug-in even suggests using String instead.

StringBuffer vs. StringBuilder

The core code implemented by StringBuffer and StringBuilder is basically the same, and much of the code is common. Both classes are inherited from the abstract class AbstractStringBuilder

Let's look at the differences from the construction method to the append method. Let's start with StringBuilder construction method:

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
}

The super method is the construction method of the AbstractStringBuilder The same is true for implementations in the construction methods corresponding to StringBuffer

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

StringBuffer and StringBuilder are the same in terms of construction methods. Here's a look at append method, StringBuilder implementation is as follows:

@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

StringBuffer approach is as follows:

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

Obviously, the only difference in StringBuffer append method implementation, except that the toStringCache variable is internally assigned null is that it is synchronized with synchronized

toStringCache is a string that is used to cache the last time the toString method is called, and the value changes when StringBuffer content changes.

By comparing the append method above, we can easily find that StringBuffer is thread-safe and StringBuilder is non-thread-safe. Of course, using synchronized synchronization can reduce performance a lot.

The underlying implementation of StringBuffer and StringBuilder

StringBuffer and StringBuilder call the construction method of the parent class:

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

With this construction method we can see that the key property they use to process string information is value At initialization, an array of char[] or value values, with a length of the incoming string length of plus 16 is initialized to store the actual string.

After calling the parent class construct method, the respective end methods are called (see the previous code), and the core processing in it calls the parent class's append method:

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

In the above code, the str.getChars method is used to stitch incoming str strings and fill them after the original value array. count is used to record the length already used in the current value number.

 Java interview question: Talk about the difference between String, StringBuffer, StringBuilder?2

So, where does thread insecurity occur when synchronization operations are not synchronized T he count+=len in the code above is not an atomic operation. F or example, count current count is 5, both threads perform the operation at the same time, get a value of 5, assign a value to count after the addition, and both threads are assigned 6 instead of 7. At this point, there is a thread insecurity.

Why String is designed to be immutable

Designing String as immutable in Java is the result of a combination of factors for the following reasons:

1, string constant pool needs, if the string is variable, change one object will affect another independent object. Unchanged This is also a prerequisite for the existence of a string constant pool.

2. Hash codes for objects in Java String are frequently used, such as in containers such as HashMap. The string unchanged guarantees the uniqueness of the hash code and can be cached and used in the direction.

3, security, to ensure that String when the parameters are passed to stay the same, to avoid security risks. For example, in the database user name, password, access path and other transmission process remains unchanged, to prevent changing the string pointing to the value of the object is changed.

4, because the string variable is immutable, in multithreaded can be shared for use.

brief summary

Simply rote interview questions we will all, but in the process of remembering the interview questions to learn more about the underlying implementation principles, not only to help understand "why", but also to learn more relevant knowledge and principles.

In this article, you've simplified the steps of copying, array expansion, and so on for StringBuilder and StringBuffer internal data, so interested friends can continue to delve back into the source code.

Here's W3Cschool编程狮 about the Java interview question: Talk about the differences between Stringing, StringBuffer, StringBuilder? Related to the introduction, I hope to help you.