Home  >  Article  >  Java  >  Java StringBuilder and StringBuffer source code analysis

Java StringBuilder and StringBuffer source code analysis

高洛峰
高洛峰Original
2017-01-22 11:28:401120browse

StringBuilder and StringBuffer are two commonly used classes for operating strings. As we all know, StringBuilder is thread-unsafe, while StringBuffer is thread-safe. The former was added in JDK1.5, and the latter was available in JDK1.0. Let's analyze their internal implementation.

1. Inheritance relationship

public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
 
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence

It can be seen that the inheritance relationship of the two classes is exactly the same. Serializable is a flag that can be serialized. The CharSequence interface includes the methods charAt(), length(), subSequence(), and toString(). The String class also implements this interface. The focus here is the abstract class AbstractStringBuilder, which encapsulates the implementation of most operations of StringBuilder and StringBuffer.

2. AbstractStringBuilder

1. Variables and construction methods

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

AbstractStringBuilder uses a char[] array internally to save the string, which can be constructed When specifying the initial capacity method.

2. Capacity expansion

public void ensureCapacity(int minimumCapacity) {
  if (minimumCapacity > 0)
    ensureCapacityInternal(minimumCapacity);
}
 private void ensureCapacityInternal(int minimumCapacity) {
  // overflow-conscious code
  if (minimumCapacity - value.length > 0)
    expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
  int newCapacity = value.length * 2 + 2;
  if (newCapacity - minimumCapacity < 0)
    newCapacity = minimumCapacity;
  if (newCapacity < 0) {
    if (minimumCapacity < 0) // overflow
      throw new OutOfMemoryError();
    newCapacity = Integer.MAX_VALUE;
  }
  value = Arrays.copyOf(value, newCapacity);
}

The expansion method is ultimately implemented by expandCapacity(). In this method, the capacity is first expanded to the original capacity plus 2. If If it is still less than the specified capacity at this time, then set the new capacity to minimumCapacity. Then determine whether it overflows. If it does, set the capacity to Integer.MAX_VALUE. Finally, the value is copied, which is obviously a time-consuming operation.

3. 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;
  }

append() is the most commonly used method, and it has many forms of overloading. The above is one of them, used to append strings. If str is null, the appendNull() method will be called. This method actually appends the characters 'n', 'u', 'l', and 'l'. If it is not null, the capacity is expanded first, and then the getChars() method of String is called to append str to the end of the value. Finally, the object itself is returned, so append() can be called continuously.

3. StringBuilder

AbstractStringBuilder has implemented most of the required methods. StringBuilder and StringBuffer only need to be called. Let's take a look at the implementation of StringBuilder.

1. Constructor

public StringBuilder() {
  super(16);
}
public StringBuilder(int capacity) {
  super(capacity);
}
public StringBuilder(String str) {
  super(str.length() + 16);
  append(str);
}
public StringBuilder(CharSequence seq) {
  this(seq.length() + 16);
  append(seq);
}

It can be seen that the default capacity of StringBuilder is 16. Of course, you can also specify the initial capacity, or assign an initial value to the StringBuilder object with an existing character sequence.

2. append() method

public StringBuilder append(String str) {
  super.append(str);
  return this;
}
public StringBuilder append(CharSequence s) {
  super.append(s);
  return this;
}

There are many overloaded methods for append(), two of them are listed here. Obviously, here is the method in the parent class AbstractStringBuilder that is directly called.

3. toString()

public String toString() {
  // Create a copy, don&#39;t share the array
  return new String(value, 0, count);
}

The toString() method returns a new String object and does not share memory with the original object. In fact, the same is true for the subString() method in AbstractStringBuilder.

4. SringBuffer

StiringBuffer is similar to StringBuilder, except that in order to achieve synchronization, many methods use lSynchronized modification, such as the following method:

public synchronized int length() {
    return count;
}
public synchronized StringBuffer append(String str) {
  toStringCache = null;
  super.append(str);
  return this;
}
public synchronized void setLength(int newLength) {
  toStringCache = null;
  super.setLength(newLength);
}


As you can see, Synchronized is indeed added in front of the method.
In addition, there is a variable toStringCache in the append() and setLength() methods above. This variable is used for the cache of the most recent toString() method. This variable will be assigned a value of null whenever the StringBuffer is modified. The toString of StringBuffer is as follows:

public synchronized String toString() {
  if (toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
  }
  return new String(toStringCache, true);
}

In this method, if toStringCache is null, it will be cached first. The final returned String object is a little different. This constructor also has a parameter true. Find the source code of String and take a look:

String(char[] value, boolean share) {
  // assert share : "unshared not supported";
  this.value = value;
}

It turns out that the String object constructed by this construction method does not actually copy the string, but just points the value to the construction parameter. This is to save copying elements. time. However, this constructor has package access rights and cannot be called under normal circumstances.

Summary

StringBuilder and StringBuffer are both mutable strings. The former is thread-unsafe and the latter is thread-safe.

Most methods of StringBuilder and StringBuffer call the implementation of the parent class AbstractStringBuilder. Its expansion mechanism first changes the capacity to 2 times the original capacity plus 2. The maximum capacity is Integer.MAX_VALUE, which is 0x7fffffff.

The default capacities of StringBuilder and StringBuffer are both 16. It is best to estimate the size of the string in advance to avoid the time consumption caused by expansion.

The above is the entire content of this article. I hope it will be helpful for everyone to learn two commonly used classes for operating strings in Java, StringBuilder and StringBuffer.

For more articles related to Java StringBuilder and StringBuffer source code analysis, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn