前言
在Java中掠械,String是一個(gè)常量由缆,一旦創(chuàng)建其值后不能更改但可以共享。
如果我們把多個(gè)字符串進(jìn)行連接(拼接)操作猾蒂,就會(huì)開辟很多空間均唉,從而造成了大量內(nèi)存空間的浪費(fèi)。
為了解決這個(gè)問題肚菠,我們需要用到StringBuffer類和StringBuilder類浸卦。
這兩個(gè)類可牛逼了,它們都是可變長度的字符串類案糙,在字符串的拼接處理上大大提高了效率限嫌。
一、StringBuffer與StringBuilder的區(qū)別
共同點(diǎn):底層數(shù)據(jù)結(jié)構(gòu)都是char類型的數(shù)組时捌,都是可變的字符串怒医。
不同點(diǎn):StringBuffer線程同步的安全性高,但多線程操作時(shí)效率低奢讨。StringBuilder線程不同步稚叹,進(jìn)行多線程操作時(shí),安全性低,但效率高扒袖。
因?yàn)檫@兩個(gè)類的用法都類似塞茅,所以我就以StringBuffer類為例來講解。
二季率、StringBuffer類的定義
StringBuffer類的部分源碼:
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
從源碼中可以看出野瘦,StringBuffer是一個(gè)用final修飾的最終類,繼承了父類AbstractStringBuilder類飒泻,實(shí)現(xiàn)了Serializable接口和CharSequence接口鞭光,說明具備了兩種能力。
三泞遗、四個(gè)構(gòu)造方法
StringBuffer類的部分源碼:
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
重點(diǎn)講下這兩個(gè)構(gòu)造方法:
構(gòu)造方法:StringBuffer()
方法描述:構(gòu)造一個(gè)沒有字符的字符串緩沖區(qū)惰许,初始容量為16。
構(gòu)造方法:StringBuffer(String str)
方法描述:構(gòu)造一個(gè)初始化為指定字符串內(nèi)容的字符串緩沖區(qū)史辙,初始容量為str.length() + 16汹买。
實(shí)例:
package cn.tkr.demo;
public class MyStringBuffer {
public static void main(String[] args) {
StringBuffer sb1 = new StringBuffer();
System.out.println("sb1字符緩沖區(qū)的容量:" + sb1.capacity()); //獲取當(dāng)前StringBuffer的容量
StringBuffer sb2 = new StringBuffer("LoveJava");
System.out.println("sb2字符緩沖區(qū)的容量:" + sb2.capacity()); //獲取當(dāng)前StringBuffer的容量
}
}
運(yùn)行結(jié)果:
sb1字符緩沖區(qū)的容量:16
sb2字符緩沖區(qū)的容量:24
實(shí)例分析:調(diào)用無參數(shù)構(gòu)造函數(shù),sb1字符緩沖區(qū)的初始容量為16聊倔,調(diào)用有參數(shù)構(gòu)造函數(shù)晦毙,初始容量為字符串的長度(8) + 16,所以初始容量為24方库。
四结序、StringBuffer的常用方法
注: append(...)中的...代表各種類型的參數(shù),如append(int i)纵潦、append(char c)徐鹤、append(String str)等
五、StringBuffer的擴(kuò)容原理
擴(kuò)容原理:
StringBuffer的底層數(shù)組結(jié)構(gòu)用的是char類型的數(shù)組邀层。
所以返敬,當(dāng)我們使用StringBuffer對象的append(...)方法追加數(shù)據(jù)時(shí),如果char類型數(shù)組的長度無法容納我們追加的數(shù)據(jù)寥院,StringBuffer就會(huì)進(jìn)行擴(kuò)容劲赠。
擴(kuò)容時(shí)會(huì)用到Arrays類中的copyOf(...)方法,每次擴(kuò)容的容量大小是原來的容量的2倍加2秸谢。
注: copyOf(...)中的...代表各種類型的參數(shù)凛澎,如
copyOf(int[] original, int newLength)、copyOf(char[] original, int newLength)等
實(shí)例源碼分析:
假設(shè)我現(xiàn)在調(diào)用了append(String str)方法估蹄,追加了一個(gè)字符串(char類型數(shù)組的長度無法容納的字符串)塑煎。
append(String str)方法源碼:
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
方法中通過super.append(str)調(diào)用了父類的append(String str)方法。
父類的append(String str)方法源碼:
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;
}
重點(diǎn)來了臭蚁,這里的ensureCapacityInternal(count + len)就是一個(gè)擴(kuò)容相關(guān)的方法最铁,變量count是一個(gè)全局變量讯赏,并沒有實(shí)際的值,變量len是我們追加進(jìn)來的字符串的長度冷尉。
也就是說漱挎,我們追加進(jìn)來的字符串的長度會(huì)傳遞給ensureCapacityInternal(int minimumCapacity)方法。
再來看看ensureCapacityInternal(int minimumCapacity)方法的源碼:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
其中雀哨,minimumCapacity指我們追加進(jìn)來的字符串的長度磕谅,value是一個(gè)全局的char類型的數(shù)組名。
也就說震束,value.length指數(shù)組的長度怜庸,那如果(minimumCapacity - value.length > 0)這個(gè)條件成立当犯,也就意味著垢村,char類型數(shù)組的長度無法容納我們追加的字符串的長度。
這時(shí)嚎卫,就需要使用Arrays類中的copyOf(char[] original, int newLength)方法進(jìn)行擴(kuò)容嘉栓。
方法:
copyOf(char[] original, int newLength)
描述:復(fù)制指定的數(shù)組,截?cái)嗷蚴褂孟鄳?yīng)的默認(rèn)值進(jìn)行填充
該方法的第一個(gè)參數(shù)是源數(shù)組名拓诸,所以要傳遞的是value侵佃。
第二個(gè)參數(shù)是新數(shù)組長度,新數(shù)組長度的值是通過newCapacity(int minCapacity)方法來計(jì)算并返回的值奠支。
newCapacity(int minCapacity)方法的源碼:
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
這個(gè)方法會(huì)返回一個(gè)新的容量大胁霰病(即新數(shù)組長度),每次擴(kuò)容的容量大小是原來的容量的2倍加2倍谜。
六迈螟、最后
感謝你看到這里,說的都是自己的一些看法和見解尔崔,如有不對答毫,請指正!覺得文章對你有幫助的話不妨給我點(diǎn)個(gè)贊季春,每天都會(huì)分享java相關(guān)技術(shù)文章或行業(yè)資訊洗搂,歡迎大家關(guān)注和轉(zhuǎn)發(fā)文章!