variability

First let’s take a look at the String source

  

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

As you can see, the String class uses an array of final keyword characters to hold strings, so it is immutable.

Note: In Java, the final keyword can be used to modify classes, methods, and variables (including member and local variables)

1. When you modify a class with final, it indicates that the class cannot be inherited. That is, if a class is never inherited, it can be modified with final.

2. Final modifier methods cannot be overridden.

3. When final modifies a base data type, it means that the value of the base data type cannot be changed once initialized. When final modifies a reference type, it cannot be made to point to any other object after it is initialized, but the contents of the object to which the reference refers can change.

StringBuilder StringBuffer

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
...
}
public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
...
}
Copy the code

AbstractStringBuilder class AbstractStringBuilder class AbstractStringBuffer class AbstractStringBuilder class

  

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

AbstractStringBuilder, StringBuffer AbstractStringBuilder, StringBuffer AbstractStringBuilder

Thread safety

Objects in strings are immutable and can be thought of as constants, thread-safe.

Let’s move on to the StringBuffer source code, where I’ve randomly captured some of the methods in the source code

/ * * * @ throws StringIndexOutOfBoundsException {@ inheritDoc} * * / @ @ since 1.2 Override public synchronized String substring(int start, int end) {return super.substring(start, end);
      }
  
     /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
     @Override
     public synchronized StringBuffer insert(int offset, Object obj) {
         toStringCache = null;
         super.insert(offset, String.valueOf(obj));
         returnthis; } /** * @override public int indexOf(String STR) { synchronization achieved via invocations of other StringBuffer methodsreturn super.indexOf(str);
     }
Copy the code

As you can see from the source code, StringBuffer places synchronization locks on methods or on invoked methods, so it is thread-safe.

Take a look at some of the methods in the StringBuilder source code

    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    
    /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
    @Override
    public StringBuilder insert(int index, char[] str, int offset,
                                 int len)
    {
        super.insert(index, str, offset, len);
        return this;
    }

    /**
      * @throws StringIndexOutOfBoundsException {@inheritDoc}
      */
    @Override
    public StringBuilder replace(int start, int end, String str) {
        super.replace(start, end, str);
        return this;
    }
Copy the code

As you can see from the source, StringBuilder does not lock methods synchronously, so it is not thread-safe.

performance

Each time a String type is changed, a new String is generated and a pointer is pointed to the new String.

A StringBuffer operates on the StringBuffer object itself each time, rather than generating new objects and changing object references.

Using StringBuilder in the same situation yields only 10% to 15% performance improvement over using StringBuffer, but at the risk of multithreading insecurity.

1. Operate on a small amount of data: String

2, single thread operation string buffer manipulation of large amounts of data: StringBuilder

3. Multithreading manipulates large amounts of data in string buffers: StringBuffer