StringBuffer and StringBuilder source code parsing (and String)

refer to:

 https://blog.csdn.net/rusbme/article/details/51389623

https://blog.csdn.net/matrix5267/article/details/62423340

String String constant
StringBuffer String variable (thread safe)

StringBuilder string variable (not thread safe)


 String is an immutable object, so every time the String type is changed, it is actually equivalent to generating a new String object, and then pointing the pointer to the new String object, so it is best not to use strings that frequently change the content. String , because every time an object is generated, it will affect the performance of the system, especially when there are too many reference objects in the memory, the JVM's GC will start to work, and the speed will be quite slow.

String a= new String("hello");

1: An a object reference is defined in the stack memory, pointing to the memory address of the value "hello" in the heap memory. Finally opened up a memory space

2: Redefine an a object reference in the stack memory, first point to the memory address of "hello" in the heap memory, and then point to the address of "hello" in the heap memory after new. Finally, two spaces are opened up. The first space has no object references and will be garbage collected by the JVM.

str += "andy";

Isn't the value of str also changed?

In fact, the above code has opened up 3 spaces in memory, namely: "hello", "andy", "helloandy", their heap memory size is fixed, and finally str points to the heap address of "helloandy". When StringBuffer is used, it will only open up a memory space, and you can use append to add operations such as delete.


First let's look at the inheritance system of the two classes

public final class StringBuilder extends AbstractStringBuilder implements
        Appendable, CharSequence, Serializable;

public final class StringBuffer extends AbstractStringBuilder implements
        Appendable, Serializable, CharSequence

AbstravtStringBuilder类

private char[] value;
    static final int INITIAL_CAPACITY = 16;
    AbstractStringBuilder() {
        value = new char[INITIAL_CAPACITY];
    }

    AbstractStringBuilder(int capacity) {
        if (capacity < 0) {
            throw new NegativeArraySizeException(Integer.toString(capacity));
        }
        value = new char[capacity];
    }
      AbstractStringBuilder(String string) {
        count = string.length();
        shared = false;
        value = new char[count + INITIAL_CAPACITY];
        string.getCharsNoCheck(0, count, value, 0);
    }

Constructor:

//The construction methods of the two classes are exactly the same, both call the constructor of the parent class, and leave 16 spaces
publicStringBuilder() {
    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);
}

The default initial capacity is 16, of course, we can also set the capacity ourselves; then we look at the splicing process

final void append0(char[] chars) {
        int newCount = count + chars.length;
        if (newCount > value.length) {
            enlargeBuffer(newCount);
        }
        System.arraycopy(chars, 0, value, count, chars.length);
        count = newCount;
    }

Next, let's take a look at the SB  expansion process .

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);
    }

Try to expand the new capacity to 2 times the size + 2. If the capacity is not enough, directly expand to the required capacity. Therefore, when we create SB, we can estimate the length of the new string to properly avoid multiple expansions, which will affect efficiency.


Basic method:
append

//Look at StringBuilder first
public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

//StringBuffer, CharSequence, char[] are similar
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

//boolean, char, long, float, double are similar
public StringBuilder append(int i) {
    super.append(i);
    return this;
}

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

//StringBuffer, CharSequence, char[] are similar
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

//boolean, char, long, float, double are similar
public synchronized StringBuffer append(int i) {
    toStringCache = null;
    super.append(i);
    return this;
}

insert

//StringBuilder
public StringBuilder insert(int index, char[] str, int offset,
                            int len)
{
    super.insert(index, str, offset, len);
    return this;
}

public StringBuilder insert(int offset, Object obj) {
        super.insert(offset, obj);
        return this;
}

public StringBuilder insert(int offset, int i) {
    super.insert(offset, i);
    return this;
}

//StringBuffer
publicsynchronized StringBuffer insert(int index, char[] str, int offset,
                                        int len)
{
    toStringCache = null;
    super.insert(index, str, offset, len);
    return this;
}

public synchronized StringBuffer insert(int offset, Object obj) {
    toStringCache = null;
    super.insert(offset, String.valueOf(obj));
    return this;
}

public StringBuffer insert(int offset, int i) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of i to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, i);
    return this;
}
 
 
  • 3
  • 4
  • 5

delete

//StringBuilder
publicStringBuilder delete(int start, int end) {
    super.delete(start, end);
    return this;
}

public StringBuilder deleteCharAt(int index) {
    super.deleteCharAt(index);
    return this;
}

public StringBuilder replace(int start, int end, String str) {
    super.replace(start, end, str);
    return this;
}
//StringBuffer
public synchronized StringBuffer delete(int start, int end) {
    toStringCache = null;
    super.delete(start, end);
    return this;
}

public synchronized StringBuffer deleteCharAt(int index) {
    toStringCache = null;
    super.deleteCharAt(index);
    return this;
}

public synchronized StringBuffer replace(int start, int end, String str) {
    toStringCache = null;
    super.replace(start, end, str);
    return this;
}

reverser


public StringBuilder reverse() {
    super.reverse();
    return this;
}

publicsynchronized StringBuffer reverse() {
    toStringCache = null;
    super.reverse();
    return this;
}

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

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

Unique to StringBuffer:


//If a method modifies the value, there will be a problem using the length() method synchronously
public synchronized int length() {
    return count;
}

public synchronized int capacity() {
    return value.length;
}

public synchronized void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > value.length) {
        expandCapacity(minimumCapacity);
    }
}

//The same reason, this also adds synchronized
public synchronized char charAt(int index) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    return value[index];
}

public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                  int dstBegin)
{
    super.getChars(srcBegin, srcEnd, dst, dstBegin);
}
public synchronized void setLength(int newLength) {
    toStringCache = null;
    super.setLength(newLength);
}

public synchronized void setCharAt(int index, char ch) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    toStringCache = null;
    value[index] = ch;
}
public synchronized String substring(int start) {
    return substring(start, count);
}

public synchronized String substring(int start, int end) {
    return super.substring(start, end);
}

publicsynchronized CharSequence subSequence(int start, int end) {
    return super.substring(start, end);
}




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325816516&siteId=291194637