長久以來,咱們被教導字符串的鏈接最好用StringBuffer、StringBuilder,可是咱們殊不知道這二者之間的區別.跟字符串相關的一些方法中老是有CharSequence、StringBuffer、StringBuilder、String,他們之間到底有什麼聯繫呢?html
下面先貼上這四者的定義(來自JDK1.6)java
CharSequence是一個定義字符串操做的接口,StringBuffer、StringBuilder、String中都實現了這個接口.數組
//CharSequence定義 public interface CharSequence //StringBuffer定義 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence //StringBuilder定義 public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence //String定義 public final class String implementsjava.io.Serializable, Comparable<String>, CharSequence
String 是java中的字符串,它繼承於CharSequence。
String類所包含的API接口很是多。爲了便於從此的使用,我對String的API進行了分類,並都給出的演示程序。安全
String 和 CharSequence 關係
String 繼承於CharSequence,也就是說String也是CharSequence類型。
CharSequence是一個接口,它只包括length(), charAt(int index), subSequence(int start, int end)這幾個API接口。除了String實現了CharSequence以外,StringBuffer和StringBuilder也實現了CharSequence接口。
也就是說,CharSequence其實也就是定義了字符串操做的接口,其餘具體的實現是由String、StringBuilder、StringBuffer完成的,String、StringBuilder、StringBuffer均可以轉化爲CharSequence類型。app
StringBuilder 和 StringBuffer 的區別less
StringBuilder 和 StringBuffer都是可變的字符序列。它們都繼承於AbstractStringBuilder,實現了CharSequence接口。
可是,StringBuilder是非線程安全的,而StringBuffer是線程安全的。函數
它們之間的關係圖以下:
ui
下面咱們來分析一下String、StringBuffer、StringBuilder具體的構造函數,瞭解他們是怎麼構造出來的,再看看具體的字符串鏈接操做。this
String的構造函數(幾個常見的構造函數)spa
public String() { this.offset = 0; this.count = 0; this.value = new char[0]; } /** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { int size = original.count; char[] originalValue = original.value; char[] v; if (originalValue.length > size) { // The array representing the String is bigger than the new // String itself. Perhaps this constructor is being called // in order to trim the baggage, so make a copy of the array. int off = original.offset; v = Arrays.copyOfRange(originalValue, off, off + size); } else { // The array representing the String is the same // size as the String, so no point in making a copy. v = originalValue; } this.offset = 0; this.count = size; this.value = v; } /** * Allocates a new {@code String} so that it represents the sequence of * characters currently contained in the character array argument. The * contents of the character array are copied; subsequent modification of * the character array does not affect the newly created string. * * @param value * The initial value of the string */ public String(char[] value) { this.offset = 0; this.count = value.length; this.value = StringValue.from(value); }
再看看String中具體的Concat函數
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } char[] buf = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf); }
從Concat函數中,咱們能夠知道在對字符串使用concat操做後,具體的操做new出一個等同於兩個字符串鏈接總長度的新的char數組,而後將兩個字符串複製到新的char數組中,而後返回一個新的String對象。
StringBuilder常見構造函數
public StringBuffer() { super(16); } public StringBuffer(int capacity) { super(capacity); }
從StringBuilder的構造函數中,咱們能夠看見StringBuilder直接調用父類(AbstractStringBuilder)的構造函數,咱們再看看AbstractStringBuilder的構造函數
abstract class AbstractStringBuilder implements Appendable, CharSequence { final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; /** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; /** * This no-arg constructor is necessary for serialization of subclasses. */ AbstractStringBuilder() { } /** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; } //其餘的一些邏輯 }
從AbstractStringBuilder的構造函數中,咱們能夠看出StringBuilder中存儲字符串其實用的是一個char數組,capacity其實就是指定這個char數組的大小。
下面咱們再從StringBuilder中的append函數看看他具體是怎麼作的(以 append(String str) 爲例看看)。
public StringBuilder append(String str) { super.append(str); return this; }
又是直接調用父類(AbstractStringBuilder)的append方法,再跟到父類中去看看。
/** * value 用來存儲字符串. */ char value[]; /** * 有效字符串的數目. */ int count; public AbstractStringBuilder append(String str) { if (str == null) { str = "null"; } int len = str.length(); if (len == 0) { return this; } int newCount = count + len; if (newCount > value.length) { expandCapacity(newCount); } //getChars將字符串複製到指定的位置 str.getChars(0, len, value, count); count = newCount; return this; }
上面的邏輯仍是比較簡單的,在append(str)函數調用的時候,首先會判斷原來用於存儲字符串的values的字符串數組有沒有足夠的大小來存儲將要新添加入StringBuilder的字符串。若是不夠用,那麼就調用expandCapacity(int minimumCapacity)讓容量翻兩倍(通常是擴大兩倍,特殊狀況見代碼),若是夠用,那麼就直接添加進去。
/** * This implements the expansion semantics of ensureCapacity with no * size check or synchronization. */ void expandCapacity(int minimumCapacity) { int newCapacity = (value.length + 1) * 2; if (newCapacity < 0) { newCapacity = Integer.MAX_VALUE; } else if (minimumCapacity > newCapacity) { newCapacity = minimumCapacity; } value = Arrays.copyOf(value, newCapacity); }
StringBuffer的構造函數
/** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */ public StringBuffer() { super(16); } /** * Constructs a string buffer with no characters in it and * the specified initial capacity. * * @param capacity the initial capacity. * @exception NegativeArraySizeException if the <code>capacity</code> * argument is less than <code>0</code>. */ public StringBuffer(int capacity) { super(capacity); }
StringBuffer也是直接調用父類(AbstractStringBuilder)的構造函數,那麼咱們從上面的分析中,就能夠知道StringBuffer其實也是利用char[]類型的數組來保存字符串數組的。
再看看StringBuffer的append函數
public synchronized StringBuffer append(String str) { super.append(str); return this; }
仍是調用父類的append函數,可是在這裏有值得注意的地方,StringBuffer的append函數有一個synchronized標識符,也就是說StringBuffer中的append函數是線程安全的,經過繼續查閱其餘StringBuffer中的函數,咱們也能夠發現他們有synchronized標識符,這就不難理解爲何StringBuffer是線程安全的,可是很明顯加上線程控制會拖慢程序運行的速度,因此若是不須要線程控制,那麼最好就用StringBuilder。
//下面只是節選一些StringBuffer中的函數 synchronized StringBuffer append(char ch) synchronized StringBuffer append(char[] chars) synchronized StringBuffer append(char[] chars, int start, int length) synchronized StringBuffer append(Object obj) synchronized StringBuffer append(String string) synchronized StringBuffer append(StringBuffer sb) synchronized StringBuffer append(CharSequence s) synchronized StringBuffer append(CharSequence s, int start, int end) synchronized StringBuffer insert(int index, char ch) synchronized StringBuffer insert(int index, char[] chars) synchronized StringBuffer insert(int index, char[] chars, int start, int length) synchronized StringBuffer insert(int index, String string) StringBuffer insert(int index, Object obj)
可能不少同窗會想了解String中的+和StringBuilder.append的效率,以及糾結要用哪一個。我在網上發現有人已經寫了一篇文章,分享給你們在Java中鏈接字符串時是使用+號仍是使用StringBuilder。
參考連接
在Java中鏈接字符串時是使用+號仍是使用StringBuilder
String詳解, String和CharSequence區別, StringBuilder和StringBuffer的區別 (String系列之1)