您好,登錄后才能下訂單哦!
概述
StringBuilder和StringBuffer是兩個(gè)容易混淆的概念,本文從源碼入手,簡(jiǎn)單看二者的異同。
容易知道的是,這兩者有一個(gè)是線程安全的,而且線程安全的那個(gè)效率低。
java doc里面的說明
java doc是寫源碼的人寫的注釋,先看java doc。
StringBuilder
A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
The principal operations on a StringBuilder are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string builder. The append method always adds these characters at the end of the builder; the insert method adds the characters at a specified point.
For example, if z refers to a string builder object whose current contents are "start", then the method call z.append("le") would cause the string builder to contain "startle", whereas z.insert(4, "le") would alter the string builder to contain "starlet".
In general, if sb refers to an instance of a StringBuilder, then sb.append(x) has the same effect as sb.insert(sb.length(), x).
Every string builder has a capacity. As long as the length of the character sequence contained in the string builder does not exceed the capacity, it is not necessary to allocate a new internal buffer. If the internal buffer overflows, it is automatically made larger.
Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that java.lang.StringBuffer be used.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
Since:
1.5
Author:
Michael McCloskey
See Also:
java.lang.StringBuffer
java.lang.String
StringBuffer
A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified. At any point in time it contains some particular sequence of characters, but the length and content of the sequence can be changed through certain method calls.
String buffers are safe for use by multiple threads. The methods are synchronized where necessary so that all the operations on any particular instance behave as if they occur in some serial order that is consistent with the order of the method calls made by each of the individual threads involved.
The principal operations on a StringBuffer are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string buffer. The append method always adds these characters at the end of the buffer; the insert method adds the characters at a specified point.
For example, if z refers to a string buffer object whose current contents are "start", then the method call z.append("le") would cause the string buffer to contain "startle", whereas z.insert(4, "le") would alter the string buffer to contain "starlet".
In general, if sb refers to an instance of a StringBuffer, then sb.append(x) has the same effect as sb.insert(sb.length(),
Whenever an operation occurs involving a source sequence (such as appending or inserting from a source sequence), this class synchronizes only on the string buffer performing the operation, not on the source. Note that while StringBuffer is designed to be safe to use concurrently from multiple threads, if the constructor or the append or insert operation is passed a source sequence that is shared across threads, the calling code must ensure that the operation has a consistent and unchanging view of the source sequence for the duration of the operation. This could be satisfied by the caller holding a lock during the operation's call, by using an immutable source sequence, or by not sharing the source sequence across threads.
Every string buffer has a capacity. As long as the length of the character sequence contained in the string buffer does not exceed the capacity, it is not necessary to allocate a new internal buffer array. If the internal buffer overflows, it is automatically made larger.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.
Since:
JDK1.0
Author:
Arthur van Hoff
See Also:
java.lang.StringBuilder
java.lang.String
javadoc小結(jié)
從上面可以看出:
StringBuffer和StringBuilder都可以認(rèn)為是可變的String。
StringBuffer是線程安全的,先出現(xiàn),在JDK1.0的時(shí)候就有了。
StringBuilder是非線程安全的,后出現(xiàn),在JDK1.5才有。
二者的接口完全一樣,StringBuilder更快。
其實(shí),正常的用,知道這幾點(diǎn)就好了,不過還是想看看源碼里面怎么實(shí)現(xiàn)的。
源碼
如何實(shí)現(xiàn)線程安全
看源碼可以知道,這二者都繼承了一個(gè)抽象類AbstractStringBuilder
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
代碼量也不是很大,StringBuilder440行代碼,StringBuffer718行代碼,最多的是AbstractStringBuilder,一共1440行代碼。
看代碼從幾個(gè)角度看,一是一些關(guān)鍵的內(nèi)部結(jié)構(gòu)是怎么樣的,二是我們常用的函數(shù)是怎么實(shí)現(xiàn)的。因?yàn)镾tring是不可變的,是放在常量池里面的。猜測(cè)StringBuilder和StringBuffer應(yīng)該是用char數(shù)組實(shí)現(xiàn)的。
/** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count;
可以看出,用value存數(shù)據(jù),用一個(gè)count表示長(zhǎng)度。
看幾個(gè)常見方法的不同實(shí)現(xiàn)。
StringBuffer
@Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } /** * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override public synchronized StringBuffer insert(int offset, String str) { toStringCache = null; super.insert(offset, str); return this; } @Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
StringBuilder
@Override public StringBuilder append(String str) { super.append(str); return this; } /** * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override public StringBuilder insert(int offset, String str) { super.insert(offset, str); return this; } @Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
由代碼可知,大部分情況想,StrinbBuffer只是增加了一個(gè)synchronized關(guān)鍵字來保證線程安全。但toString方法不同,這個(gè)后面再說。
初始化大小和如何增長(zhǎng)
既然實(shí)際上是一個(gè)數(shù)組,那么數(shù)組開始的大小和增長(zhǎng)的方法就很重要,我們通過代碼看一下。
/** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */ public StringBuffer() { super(16); } /** * Constructs a string builder with no characters in it and an * initial capacity of 16 characters. */ public StringBuilder() { super(16); }
可以看到,這兩個(gè)默認(rèn)構(gòu)造函數(shù)都說明默認(rèn)的數(shù)組大小是16。
為什么是16呢?我沒想明白。
接下來關(guān)心如何增長(zhǎng)的?我們看看append的實(shí)現(xiàn)
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; } /** * This method has the same contract as ensureCapacity, but is * never synchronized. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); } /** * This implements the expansion semantics of ensureCapacity with no * size check or synchronization. */ 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); }
上面三個(gè)方法說明了如何擴(kuò)容。
把當(dāng)前的容量*2+2
如果新增加的長(zhǎng)度大于這個(gè)值,則設(shè)為新增加的值
如果溢出,則拋出OutOfMemoryError
StringBuffer中toString的實(shí)現(xiàn)
/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */ private transient char[] toStringCache; @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } @Override public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
可以看到,定義了一個(gè)數(shù)組toStringCache,每次數(shù)據(jù)有變化,都把這個(gè)設(shè)置為null。在toString的時(shí)候,再重新從當(dāng)前數(shù)據(jù)里面拿。
transient關(guān)鍵字是為了避免這個(gè)數(shù)組被序列化。
小結(jié)
其實(shí)java本身的源碼寫的還是比較簡(jiǎn)單的,學(xué)習(xí)知識(shí)如果能從源碼入手,能夠更深入的理解很多原理。本文只是簡(jiǎn)單的列舉了一部分源碼,簡(jiǎn)單說明StringBuffer和StringBuilder的異同。有興趣的朋友可以自己看一下。
以上這篇從源碼角度簡(jiǎn)單看StringBuilder和StringBuffer的異同(全面解析)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。