Java源碼深度分析String與StringBuffer及StringBuilder詳解
String的字符串是不可變的,StringBuffer和StringBuilder是可變的
String:是字符常量,適用于少量的字符串操作的情況。
StringBuilder:適用于單線程下在字符緩沖區(qū)進(jìn)行大量操作的情況 。
StringBuffer:適用多線程下在字符緩沖區(qū)進(jìn)行大量操作的情況。
StringBuffer和StringBuild的區(qū)別
StingBuffer是線程安全的,StringBuild是線程不安全的。
然后再往上查看,就會發(fā)現(xiàn)他兩都是調(diào)用了AbstractStringBuilder類來實現(xiàn)的。
我們不是說StringBuffer和StringBuilder創(chuàng)建的字符串是可變的。
至于源碼就直接看源碼,就直接在源碼當(dāng)中詳細(xì)的體現(xiàn)出來了。
在這篇博客我主要說一下StringBuffer,因為StingBuild和StringBuffer的方法幾乎一樣,我在這就不做過多的詳細(xì)贅述了。
創(chuàng)建StringBuffer()
第一種創(chuàng)建方法:
StringBuffer stringBuffer = new StringBuffer();
在使用這個方法創(chuàng)建的Buffer字符串的時候,看底層代碼它就調(diào)用了這個方法:
public StringBuffer() { super(16); }
它雖然沒有給傳入?yún)?shù),它是它默認(rèn)的是一個數(shù)組長度為16的字符串。
在往上看這個向上傳的父類方法就更加簡單明了:
AbstractStringBuilder(int capacity) { value = new char[capacity]; }
直接創(chuàng)建長度為16的字符型數(shù)組。
第二種創(chuàng)建方法:
StringBuffer stringBuffer = new StringBuffer(5);
直接給定要創(chuàng)建的字符長度。
底層源碼:
public StringBuffer(int capacity) { super(capacity); }
第三種創(chuàng)建方法:
StringBuffer stringBuffer = new StringBuffer(“Xin”);
在創(chuàng)建的時候,初始給定初始化的一個字符串。
那么在這個時候就要考慮它的底層保存字符串的數(shù)組要創(chuàng)建幾位呢? 看源碼,源碼會告訴我們一切的。
public StringBuffer(String str) { super(str.length() + 16); append(str); }
源碼當(dāng)中明確的告訴了我們,在這種情況下創(chuàng)建的字符串,底層數(shù)組長度是初始字符串的長度加16.
小小的總結(jié)一下:
在創(chuàng)建StringBuffer或StringBuilder字符串的時候如果沒有給長度,默認(rèn)為16的長度,給長度的話,就是給定的長度,給的是字符串的話,默認(rèn)初始長度就是字符串的長度加16
添加功能
public StringBuffer append(String str)
代碼演示一下,這還要一個點考慮一下:
public class Demo01 { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("Xin_"); //stringBuffer.length = 4 stringBuffer.append("Chen_"); //stringBuffer.length = 9 stringBuffer.append("Yu_"); //stringBuffer.length = 12 stringBuffer.append("Chen_"); //stringBuffer.length = 17 stringBuffer.append("Xi"); //stringBuffer.length = 19 System.out.println(stringBuffer); } }
在不停的添加下去,當(dāng)數(shù)組的長度到達(dá)16的時候,要考慮一下擴(kuò)容的問題,如何擴(kuò)容?
老規(guī)矩,看源代碼,一切都在代碼里:
照著這個步驟一步一步的點進(jìn)去,到達(dá)最后的源代碼:
MAX_ARRAY_SIZE的長度為:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
所以最后是 0x7fffffff-8
總的來說,每次底層數(shù)組擴(kuò)容為上次的2倍加2的長度。
刪除功能
第一種刪除字符串中指定位置的字符
public StringBuffer deleteCharAt(int index)
這個指定刪除字符串當(dāng)中明確的第幾個索引。只刪除一個元素
注意這里是索引的位置,不是第幾個元素。
public class Demo01 { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer("Xin_Chen_Yu_Chen_Xi"); System.out.println(stringBuffer); stringBuffer.deleteCharAt(4); System.out.println(stringBuffer); } }
源碼其實也不難,就不重視的看了,在這主要看一經(jīng)過刪除操作,它的字符串長度是如何減少的。
刪除字符串當(dāng)中指定區(qū)間的字符串
public StringBuffer delete(int start,int end)
牢記在Java當(dāng)中大多情況下,數(shù)組下標(biāo)索引都是左閉右開的。
在下面的代碼當(dāng)中,我刪除的就是"Chen_"這5個字符
public class Demo01 { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer("Xin_Chen_Yu_Chen_Xi"); System.out.println(stringBuffer); stringBuffer.delete(4,9); System.out.println(stringBuffer); } }
和上面一樣??匆谎墼创a,如何處理刪除后的字符串的長度:
它兩的底層都調(diào)用的是native本地反方,交由計算機(jī)系統(tǒng)完成。
替換功能
就是將字符串中其中某一段的字符串替換為其他的字符串。
public StringBuffer replace(int start,int end,String str)
public class Demo01 { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer("Xin_Chen_Yu_Chen_Xi"); System.out.println(stringBuffer); stringBuffer.replace(4,8,"Gu_Chen"); System.out.println(stringBuffer); } }
這里也都是數(shù)組的下標(biāo)索引,所以就是從0開始計數(shù)的。
替換這也同上面的一樣,也需要考慮一下底層字符串的長度問題,先看源碼:
反轉(zhuǎn)功能
這個功能就是將原字符串玩去哪反轉(zhuǎn)過來,倒序保存起來。
public class Demo01 { public static void main(String[] args) { StringBuffer stringBuffer = new StringBuffer("Xin_Chen_Yu_Chen_Xi"); System.out.println(stringBuffer); stringBuffer.reverse(); System.out.println(stringBuffer); } }
也來看一下它的源代碼
最后總結(jié)一下
- String的字符串是不可變的,StringBuffer和StringBuilder是可變的
- String:是字符常量,適用于少量的字符串操作的情況。
- StringBuilder:線程不安全的,適用于單線程下在字符緩沖區(qū)進(jìn)行大量操作的情況 。
- StringBuffer:線程不安全的,適用多線程下在字符緩沖區(qū)進(jìn)行大量操作的情況。
在這幾條總計出來的說法當(dāng)中,在這再詳細(xì)說明一下為什么StringBuffer和StringBuilder是可變的。
在文章上面,我展示了許多的源碼,仔細(xì)觀察一下,Buffer和Builder修飾的方法,它最后返回的都是this,返回了,自己,就是無論什么操作,它最終都返回的是自己。
但是有些小伙伴還是有個疑問,當(dāng)它底層擴(kuò)容超過它的最大值的時候,它的數(shù)組不就要換了嗎?
這點確實是對的,但是在這我們要理清一個概念,StringBuffer引用的是底層數(shù)組名字的地址,而數(shù)組在需要換一個更大的時候,這個時候是數(shù)組的引用變化了,就是指向數(shù)組的地址變了,但是指向StringBuffer的地址是不變的。
我下來使用一個debug動圖來展示一下,相信能更好的理解一下。
主要看控制臺里的StringBuffer和value的值。我們發(fā)現(xiàn)StringBuffer值地址自始至終都沒有改變,而value的值在到達(dá)16的時候,需要擴(kuò)容的時候,就變了。這正印證了我上面所說的。
本篇博客也就到此為止了,感謝你的閱讀。如果要是還是想不清楚,特別是最后的總結(jié)部分,歡迎在評論區(qū)討論,我看到話,會第一時間共同討論,解決問題。
這也是我重讀javase基礎(chǔ)的一個系列,比起當(dāng)時初學(xué)的時候,現(xiàn)在看問題多了個高度,理解什么也相對輕松一點全面一些。學(xué)習(xí)起來更加偏向閱讀源碼來看,所以多為大家分享看源碼。
到此這篇關(guān)于Java源碼深度分析String與StringBuffer及StringBuilder詳解的文章就介紹到這了,更多相關(guān)Java String源碼分析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中String、StringBuffer和StringBuilder的區(qū)別
- Java中的String、StringBuilder、StringBuffer三者的區(qū)別詳解
- Java中StringBuilder與StringBuffer的區(qū)別
- Java中StringBuilder與StringBuffer使用及源碼解讀
- 淺析Java中StringBuffer和StringBuilder的使用
- Java StringBuffer與StringBuilder有什么區(qū)別
- 詳解Java中String,StringBuffer和StringBuilder的使用
- Java中String和StringBuffer及StringBuilder?有什么區(qū)別
- Java詳細(xì)分析String類與StringBuffer和StringBuilder的使用方法
- Java中String、StringBuffer和StringBuilder的區(qū)別與使用場景
相關(guān)文章
SpringSession 請求與響應(yīng)重寫的實現(xiàn)
這篇文章主要介紹了SpringSession 請求與響應(yīng)重寫的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11詳解在SpringBoot中@Transactional事物操作和事物無效問題排查
這篇文章主要介紹了詳解在SpringBoot中@Transactional事物操作和事物無效問題排查,本文詳細(xì)的介紹了SpringBoot中集成使用@Transactional注解操作事物以及事物開啟后無效的問題排查,需要的朋友可以參考下2021-06-06