深入String、StringBuilder、StringBuffer
目錄:
1.String
2.StringBuilder和StringBuffer
3.String、StringBuild、StringBuffer區(qū)別
1.String
(1)String的基本用法:
indexOf():返回指定字符的索引。 charAt():返回指定索引處的字符。 replace():字符串替換。 trim():去除字符串兩端空白。 split():分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。 getBytes():返回字符串的 byte 類型數(shù)組。 length():返回字符串長度。 toLowerCase():將字符串轉(zhuǎn)成小寫字母。 toUpperCase():將字符串轉(zhuǎn)成大寫字符。 substring():截取字符串。 equals():字符串比較。(2)String的特點(diǎn)
1.String不是基本數(shù)據(jù)類型,String 底層是一個(gè) char 類型的數(shù)組
2.使用 final 來定義 String 類,表示 String 類不能被繼承
3.String 對象創(chuàng)建之后,會在字符串常量池中進(jìn)行緩存,如果下次創(chuàng)建同樣的對象時(shí),會直接返回緩存的引用。
4.String內(nèi)容是不可變的但不代表引用不可以變,String 是只讀字符串,對它進(jìn)行任何操作,其實(shí)都是創(chuàng)建一個(gè)新的對象,再把引用指向該對象。不變模式的主要作用在于當(dāng)一個(gè)對象需要被多線程共享并頻繁訪問時(shí),可以保證數(shù)據(jù)的一致性。
前兩點(diǎn)可以通過源碼來解釋:
這個(gè)第3,4點(diǎn)怎么理解呢,看個(gè)例子
答案是:
再細(xì)品這兩句話
String 對象創(chuàng)建之后,會在字符串常量池中進(jìn)行緩存,如果下次創(chuàng)建同樣的對象時(shí),會直接返回緩存的引用
String內(nèi)容是不可變的但不代表引用不可以變,String 是只讀字符串,對它進(jìn)行任何操作,其實(shí)都是創(chuàng)建一個(gè)新的對象(博主認(rèn)為這個(gè)新的對象創(chuàng)建在堆區(qū)為啥呢看下圖),再把引用指向該對象
如果c也在方法區(qū)那么為啥創(chuàng)建的新的四個(gè)ghjk為啥沒有一個(gè)的引用和c一樣
(3)字符串常量池
String是字符串常量那么什么是字符串常量池?
字符串常量池位于堆內(nèi)存中,專門用來存儲字符串常量,可以提高內(nèi)存的使用率,避免開辟多塊空間存儲相同的字符串,在建字符串時(shí) JVM 會首先檢查字符串常量池,如果該字符串已經(jīng)存在池中,則返回它的引用,如果不存在,則實(shí)例化一個(gè)字符串放到池中,并返回其引用。
(4)兩種創(chuàng)建字符串對象相同嗎:String str="abc"與 String str=new String(“abc”)
答案當(dāng)然是不一樣,因?yàn)閮?nèi)存的分配方式不一樣。
String str="abc"的方式,java 虛擬機(jī)會將其分配到常量池中;而 String str=new String(“abc”) 則會被分到堆內(nèi)存中(當(dāng)然也沒這么簡單下面會講)
(5)創(chuàng)建對象個(gè)數(shù)的問題:
String str=new String(“abc”)
其實(shí)這里有兩種情況:
第一種當(dāng)常量池沒有“abc”這個(gè)字符串的話就創(chuàng)建兩個(gè)對象
當(dāng)常量池中沒有字符串“abc”的時(shí)候那么創(chuàng)建一個(gè)對象在堆區(qū),然后再在常量區(qū)創(chuàng)建一個(gè)字符串常量“abc”
博主你怎么知道你頭大?
博主:沒錯(cuò)我就是頭大
兄弟們拿刀
博主:別別別,我好好講還不行嗎
我們都知道String本質(zhì)還是一個(gè)字符串?dāng)?shù)組那么當(dāng)我們再創(chuàng)建String b=“abc”(這里如果常量區(qū)有“abc”就把這個(gè)引用賦給b,沒有就在常量區(qū)創(chuàng)建一個(gè)“abc對象”前面說了),由源碼我們知道String本質(zhì)其實(shí)是一個(gè)value[]的字符串?dāng)?shù)組,我們比較b的value和str的value發(fā)現(xiàn)他倆地址一樣,這不就驗(yàn)證了我剛才創(chuàng)建兩個(gè)的說法了嗎
第二種當(dāng)常量池有“abc”這個(gè)字符串的時(shí)候就創(chuàng)建一個(gè)對象
和上面一樣只不過b=“abc”在str=new String之前一樣去比較兩個(gè)對象的底層數(shù)組得出創(chuàng)建一個(gè)對象
2.StringBuffer和StringBuilder
(1)
存在于java.lang.StringBuilder中,我們知道String是字符串常量,不可以改變指向的對象值,只能改變指向的對象,那么StringBuilder就不一樣了,他是一個(gè)可變的字符串序列
原來StringBuilder是個(gè)字符串的緩沖區(qū),即它是一個(gè)容器,容器中可以裝很多字符串。并且能夠?qū)ζ渲械淖址M(jìn)行各種操作,它的內(nèi)部擁有一個(gè)數(shù)組用來存放字符串內(nèi)容,進(jìn)行字符串拼接時(shí),直接在數(shù)組中加入新內(nèi)容。StringBuilder會自動(dòng)維護(hù)數(shù)組的擴(kuò)容原理如下:
(2)常用的方法:
運(yùn)行結(jié)果:
這里注意append方法返回StringBuffer對象。toString()會把一個(gè)StringBuffer對象轉(zhuǎn)換成一個(gè)String對象,一個(gè)StringBuffer對象的引用是不能等于一個(gè)String對象的
StringBuffer和StringBuilder兩個(gè)用法差不多StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,char[] value,這兩種對象都是可變的。
3.String、StringBuild、StringBuffer的區(qū)別
1.String中的對象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對方法加了同步鎖或者對調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder并沒有對方法進(jìn)行加同步鎖,所以是非線程安全的。
2.每次對String 類型進(jìn)行改變的時(shí)候,都會生成一個(gè)新的String對象,然后將指針指向新的String 對象。StringBuffer每次都會對StringBuffer對象本身進(jìn)行操作,而不是生成新的對象并改變對象引用。相同情況下使用StirngBuilder 相比使用StringBuffer 僅能獲得10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)。
3.如果要操作少量的數(shù)據(jù)用 =》 String。
單線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) =》 StringBuilder。
多線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = 》StringBuffer。
總結(jié)
以上是生活随笔為你收集整理的深入String、StringBuilder、StringBuffer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还在傻傻分不清楚equal和==
- 下一篇: Date、DateFormat、Cale