前言
在Java中鳞陨,String是一個(gè)常量,一旦創(chuàng)建其值后不能更改但可以共享瞻惋。
如果我們把多個(gè)字符串進(jìn)行連接(拼接)操作厦滤,就會(huì)開(kāi)辟很多空間,從而造成了大量?jī)?nèi)存空間的浪費(fèi)歼狼。
為了解決這個(gè)問(wèn)題掏导,我們需要用到StringBuffer類(lèi)和StringBuilder類(lèi)。
這兩個(gè)類(lèi)可牛逼了羽峰,它們都是可變長(zhǎng)度的字符串類(lèi)碘菜,在字符串的拼接處理上大大提高了效率。
一限寞、StringBuffer與StringBuilder的區(qū)別
共同點(diǎn):底層數(shù)據(jù)結(jié)構(gòu)都是char類(lèi)型的數(shù)組,都是可變的字符串仰坦。
不同點(diǎn):StringBuffer線程同步的安全性高履植,但多線程操作時(shí)效率低。StringBuilder線程不同步悄晃,進(jìn)行多線程操作時(shí)玫霎,安全性低凿滤,但效率高。
因?yàn)檫@兩個(gè)類(lèi)的用法都類(lèi)似庶近,所以我就以StringBuffer類(lèi)為例來(lái)講解翁脆。
二、StringBuffer類(lèi)的定義
StringBuffer類(lèi)的部分源碼:
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
從源碼中可以看出鼻种,StringBuffer是一個(gè)用final修飾的最終類(lèi)反番,繼承了父類(lèi)AbstractStringBuilder類(lèi),實(shí)現(xiàn)了Serializable接口和CharSequence接口叉钥,說(shuō)明具備了兩種能力罢缸。
三、四個(gè)構(gòu)造方法
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è)沒(méi)有字符的字符串緩沖區(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)用無(wú)參數(shù)構(gòu)造函數(shù)息楔,sb1字符緩沖區(qū)的初始容量為16,調(diào)用有參數(shù)構(gòu)造函數(shù)扒披,初始容量為字符串的長(zhǎng)度(8) + 16值依,所以初始容量為24。
四谎碍、StringBuffer的常用方法
注: append(...)中的...代表各種類(lèi)型的參數(shù)鳞滨,如append(int i)、append(char c)蟆淀、append(String str)等
五拯啦、StringBuffer的擴(kuò)容原理
擴(kuò)容原理:
StringBuffer的底層數(shù)組結(jié)構(gòu)用的是char類(lèi)型的數(shù)組。
所以熔任,當(dāng)我們使用StringBuffer對(duì)象的append(...)方法追加數(shù)據(jù)時(shí)褒链,如果char類(lèi)型數(shù)組的長(zhǎng)度無(wú)法容納我們追加的數(shù)據(jù),StringBuffer就會(huì)進(jìn)行擴(kuò)容疑苔。
擴(kuò)容時(shí)會(huì)用到Arrays類(lèi)中的copyOf(...)方法甫匹,每次擴(kuò)容的容量大小是原來(lái)的容量的2倍加2。
注: copyOf(...)中的...代表各種類(lèi)型的參數(shù)惦费,如
copyOf(int[] original, int newLength)兵迅、copyOf(char[] original, int newLength)等
實(shí)例源碼分析:
假設(shè)我現(xiàn)在調(diào)用了append(String str)方法,追加了一個(gè)字符串(char類(lèi)型數(shù)組的長(zhǎng)度無(wú)法容納的字符串)薪贫。
append(String str)方法源碼:
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
方法中通過(guò)super.append(str)調(diào)用了父類(lèi)的append(String str)方法恍箭。
父類(lèi)的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)來(lái)了,這里的ensureCapacityInternal(count + len)就是一個(gè)擴(kuò)容相關(guān)的方法瞧省,變量count是一個(gè)全局變量扯夭,并沒(méi)有實(shí)際的值鳍贾,變量len是我們追加進(jìn)來(lái)的字符串的長(zhǎng)度。
也就是說(shuō)交洗,我們追加進(jìn)來(lái)的字符串的長(zhǎng)度會(huì)傳遞給ensureCapacityInternal(int minimumCapacity)方法骑科。
再來(lái)看看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)來(lái)的字符串的長(zhǎng)度构拳,value是一個(gè)全局的char類(lèi)型的數(shù)組名咆爽。
也就說(shuō),value.length指數(shù)組的長(zhǎng)度隐圾,那如果(minimumCapacity - value.length > 0)這個(gè)條件成立伍掀,也就意味著,char類(lèi)型數(shù)組的長(zhǎng)度無(wú)法容納我們追加的字符串的長(zhǎng)度暇藏。
這時(shí)蜜笤,就需要使用Arrays類(lèi)中的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ù)組長(zhǎng)度瓮顽,新數(shù)組長(zhǎng)度的值是通過(guò)newCapacity(int minCapacity)方法來(lái)計(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ù)組長(zhǎng)度)暖混,每次擴(kuò)容的容量大小是原來(lái)的容量的2倍加2缕贡。
最后
感謝你看到這里,看完有什么的不懂的可以在評(píng)論區(qū)問(wèn)我拣播,覺(jué)得文章對(duì)你有幫助的話(huà)記得給我點(diǎn)個(gè)贊晾咪,每天都會(huì)分享java相關(guān)技術(shù)文章或行業(yè)資訊,歡迎大家關(guān)注和轉(zhuǎn)發(fā)文章贮配!