最近在找工作,考官問我一個簡單的題目:“StringBuffer與StringBuilder的區別,它們的應用場景是什麼?”,下面小編答案分享給大家,方便以後大家學習,以此也做個備錄。
其實只要找下Google大神就有答案了:StringBuffer 與StringBuilder 中的方法和功能完全是等價的,只是StringBuffer 中的方法大都採用了synchronized 關鍵字進行修飾,因此是線程安全的,而StringBuilder 沒有這個修飾,可以被認為是線程不安全的。
為了更好的理解上述的答案,還是直接看StringBuffer與StringBuilder的源碼實作比較實在,作為一個程式猿,「有疑問,看源碼」才是正道,我可以負責任的說,當然得有條件才行!
jdk的實作中StringBuffer與StringBuilder都繼承自AbstractStringBuilder,對於多執行緒的安全與非安全看到StringBuffer中方法前面的一堆synchronized就大概了解了。
這裡隨便講講AbstractStringBuilder的實作原理:我們知道使用StringBuffer等無非就是為了提高java中字串連接的效率,因為直接使用+進行字串連接的話,jvm會創建多個String對象,因此造成一定的開銷。 AbstractStringBuilder中採用一個char數組來保存需要append的字串,char數組有一個初始大小,當append的字串長度超過當前char數組容量時,則對char數組進行動態擴展,也即重新申請一段更大的記憶體空間,然後將目前char數組拷貝到新的位置,因為重新分配記憶體並拷貝的開銷比較大,所以每次重新申請記憶體空間都是採用申請大於目前需要的記憶體空間的方式,這裡是2倍。
接下來,玩些好玩的!
在Google中出來了這麼多信息:
【
StringBuffer 始於JDK 1.0
StringBuilder 始於JDK 1.5
從JDK 1.5 開始,始於JDK 1.5
從JDK 1.5 開始,帶有字串的連接操作(+M+)是
】
我們透過一個簡單的程式來看其執行的流程:
清單1 Buffer.java
public class Buffer { public static void main(String[] args) { String s1 = "aaaaa"; String s2 = "bbbbb"; String r = null; int i = 3694; r = s1 + i + s2; for(int j=0;i<10;j++){ r+="23124"; } } }
使用指令javap -c Buffer檢視其字節碼2 Buffer類字節碼
將清單1和清單2對應起來看,清單2的字節碼中ldc指令即從常數池中加載“aaaaa”字串到棧頂,istore_1將“aaaaa”存到變量1中,後面的一樣,sipush是將一個短整型常數值(-32768~32767)推送至棧頂,這裡是常數“3694”,更多的Java指令集請查看另一篇文章“Java指令集」。 讓我們直接看到13,13~17是new了一個StringBuffer物件並呼叫其初始化方法,20~21則是先透過aload_1將變數1壓到棧頂,前面說過變數1放的就是字串常數“aaaaa”,接著透過指令invokevirtual呼叫StringBuffer的append方法將“aaaaa”拼接起來,後續的24~30同理。最後在33調用StringBuffer的toString函數獲得String結果並透過astore存到變數3。 看到這裡可能有人會說,「既然JVM內部採用了StringBuffer來連接字串了,那麼我們自己就不用用StringBuffer,直接用」+「就行了吧!」。是麼?當然不是了。俗話說”存在既有它的理由”,讓我們繼續看後面的循環對應的字節碼。 37~42都是進入for循環前的一些準備工作,37,38是將j置為1。44這裡透過if_icmpge將j與10進行比較,如果j大於10則直接跳到73,也即return語句退出函數;否則進入循環,也即47~66的字節碼。這裡我們只要看47到51就知道為什麼我們要在程式碼中自己使用StringBuffer來處理字串的連接了,因為每次執行「+」操作時jvm都要new一個StringBuffer物件來處理字串的連接,這在涉及很多的字串連接操作時開銷會很大。 更多Java—StringBuffer與StringBuilder原理與區別相關文章請關注PHP中文網!