JavaString,看這篇就夠了-創(chuàng)新互聯(lián)

String,是Java中最重要的類。這句肯定的推斷不是Java之父詹姆斯·高斯林說的,而是沉默王二說的,因此你不必懷疑它的準(zhǔn)確性。

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供桐柏網(wǎng)站建設(shè)、桐柏做網(wǎng)站、桐柏網(wǎng)站設(shè)計(jì)、桐柏網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、桐柏企業(yè)網(wǎng)站模板建站服務(wù),十載桐柏做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

關(guān)于字符串,有很多的面試題,但我總覺得理論知識(shí)繞來繞去沒多大意思。你比如說:String cmower = new String("沉默王二");定義了幾個(gè)對(duì)象?

我總覺得問我這樣的問題,就好像是在拷問我:“既然你家買了冰箱,你難道不應(yīng)該知道冰箱制冷的原理?”

再說,為什么要用String cmower = new String("沉默王二");而不是String cmower = "沉默王二";?

我勸各位面試官不要再纏住這樣的問題不放了,切記“學(xué)以致用”。理論知識(shí)如果一直是在繞彎彎,那真的毫無價(jià)值。如果要我來做面試官,我想要問的問題是:“你平常是怎么判斷兩個(gè)字符串相等的?是用equals()還是==?”

前言就說這么多。接下來,我們來探討幾個(gè)實(shí)用的知識(shí)點(diǎn)。

01、 字符串是不可變的

我們來看一下String類的定義:

public?final?class?String
????implements?java.io.Serializable,?Comparable<String>,?CharSequence?{
}

可以發(fā)現(xiàn),String類是final類型的,因此不能被繼承。

如果類可以被繼承,那么就會(huì)破壞類的不可變性機(jī)制。因?yàn)樽宇惪梢愿采w父類的方法,并且可以改變父類的成員變量值,一旦子類以父類的形式出現(xiàn)時(shí),就不能保證類是不可變的。

String類的不可變性有什么好處呢?

1)作為HashMap的鍵。

因?yàn)樽址遣豢勺兊?,因此它在?chuàng)建的時(shí)候哈希碼(hash code)就計(jì)算好了。這也就意味著每次在使用一個(gè)字符串的哈希碼的時(shí)候不用重新計(jì)算一次,這樣更加高效,很適合作為HashMap中的鍵。

2)線程安全。

同一個(gè)字符串對(duì)象可以被多個(gè)線程共享,如果訪問頻繁的話,可以省略同步和鎖等待的時(shí)間,從而提升性能。

3)字符串常量池的需要。

特別要注意的是,String類的所有方法都沒有改變字符串本身的值,都是返回了一個(gè)新的對(duì)象。

推薦閱讀:為什么 Java 字符串是不可變的?

02、 字符串常量池

在Java中,常用的創(chuàng)建字符串的方式有兩種:

String?cmower?=?"沉默王二";

String?cmowsan?=?new?String("沉默王三");

cmower使用雙引號(hào),cmowsan使用new關(guān)鍵字,它們有什么區(qū)別呢?

答案如下:

String?cmower?=?"沉默王二";
String?cmower1?=?"沉默王二";
System.out.println(cmower?==?cmower1);?//?輸出true

String?cmowsan?=?new?String("沉默王三");
String?cmowsan1?=?new?String("沉默王三");
System.out.println(cmowsan?==?cmowsan1);?//?輸出false

雙引號(hào)創(chuàng)建的相同字符串使用==判斷時(shí)結(jié)果為true,而new關(guān)鍵字創(chuàng)建的相同字符串使用==判斷時(shí)結(jié)果為false。

這是為什么呢?

String在Java中使用過于頻繁,為了避免在系統(tǒng)中產(chǎn)生大量的String對(duì)象,Java的設(shè)計(jì)者引入了“字符串常量池”的概念。

當(dāng)使用雙引號(hào)創(chuàng)建一個(gè)字符串時(shí),首先會(huì)檢查字符串常量池中是否有相同的字符串對(duì)象,如果有,則直接從常量池中取出對(duì)象引用;如果沒有,則新建字符串對(duì)象,并將其放入字符串常量池中,并返回對(duì)象引用。

這也就是說,"沉默王二"是放在字符串常量池中的,cmower和cmower1兩個(gè)字符串對(duì)象引用是相同的。

而new關(guān)鍵字創(chuàng)建的字符串對(duì)象是不涉及字符串常量池的,直接放在堆中,也就是說,雖然cmowsan和cmowsan1都叫沉默王三,但不一個(gè)人。

強(qiáng)烈建議:不要使用new關(guān)鍵字的形式創(chuàng)建字符串對(duì)象。

03、 +號(hào)和StringBuilder

由于字符串是不可變的,因此字符串在進(jìn)行拼接的時(shí)候會(huì)創(chuàng)建新的字符串對(duì)象。大家都知道,內(nèi)存是一定的,因此對(duì)象創(chuàng)建多了就會(huì)影響系統(tǒng)性能。

StringBuilder正是為了解決字符串拼接產(chǎn)生太多中間對(duì)象的問題而提供的一個(gè)類,可以通過append()方法把字符串添加到已有序列的末尾,非常高效。

那么有人在進(jìn)行字符串拼接的時(shí)候,就會(huì)產(chǎn)生疑惑:“我到底是用+號(hào)還是StringBuilder?”

我們先來看這樣一段代碼:

String?chenmo?=?"沉默";
String?wanger?=?"王二";
System.out.println(chenmo?+?wanger);

這段代碼是怎么編譯的呢?可以使用JAD(Java反編譯工具)來看一看。

String?s?=?"\u5A0C\u5910\u7CAF";
String?s1?=?"\u941C\u5B29\u7C29";
System.out.println((new?StringBuilder()).append(s).append(s1).toString());

你是不是看到了StringBuilder的影子?

沒錯(cuò),使用+號(hào)進(jìn)行字符串拼接的時(shí)候,Java編譯器實(shí)際是通過StringBuilder類來完成的。

難道可以使用+號(hào)來隨意拼接字符串?反正Java編譯器已經(jīng)自動(dòng)地為我們優(yōu)化了。

但事實(shí)并非如此,來看這樣一段代碼:

String?cmowers?=?"";
for?(int?i?=?0;?i?<?9;?i++)?{
????cmowers?+=?"沉默王二";
}
System.out.println(cmowers);

閉上眼睛先想一想,Java編譯器會(huì)怎么做?我們期望的結(jié)果是在循環(huán)外部就創(chuàng)建StringBuilder,Java編譯器能如我們所愿嗎?

JAD反編譯后的結(jié)果如下:

String?s?=?"";
for(int?i?=?0;?i?<?10;?i++)
????s?=?(new?StringBuilder()).append(s).append("\u5A0C\u5910\u7CAF\u941C\u5B29\u7C29").toString();

System.out.println(s);

這么看來,StringBuilder是在for循環(huán)內(nèi)部創(chuàng)建的,也就是說會(huì)創(chuàng)建10次。天吶,這可不是我們期望的結(jié)果!我們只希望StringBuilder創(chuàng)建一次。

沒辦法,Java編譯器是做不到的,只能靠我們自己:

StringBuilder?cmowers?=?new?StringBuilder();
for?(int?i?=?0;?i?<?9;?i++)?{
????cmowers.append("沉默王二");
}
System.out.println(cmowers);

強(qiáng)烈建議:如果只是三四個(gè)字符串的拼接,盡管使用+號(hào)操作符,別想什么性能優(yōu)化(舉個(gè)例子,你離目的地只有100米,你是打算打個(gè)出租車,還是自己步行走過去?);如果遇到多于四個(gè)字符串的拼接,或者需要用到循環(huán)來拼接,那就選擇StringBuilder。

在我年輕的時(shí)候,我還會(huì)犯這樣一個(gè)錯(cuò)誤:

StringBuilder?cmowers?=?new?StringBuilder();
for?(int?i?=?0;?i?<?9;?i++)?{
????cmowers.append("沉默王二"?+?"和他的讀者朋友們");
}
System.out.println(cmowers);

我去,竟然在append()方法的內(nèi)部使用+號(hào)!因?yàn)檫@個(gè)錯(cuò)誤,我差點(diǎn)沒被領(lǐng)導(dǎo)打死。你可要小心點(diǎn)。

04、 關(guān)于concat()

除了使用+號(hào)和StringBuilder對(duì)字符串進(jìn)行拼接,還可以使用String類的concat()方法。

concat()方法只不過是String類的一個(gè)方法而已,為什么我要單獨(dú)拎出來說呢?

因?yàn)橹拔乙贘SP頁面的EL表達(dá)式中拼接字符串,剛開始想到的是用+號(hào)操作符,但EL表達(dá)式不是Java,+號(hào)操作符是不能拼接字符串的。我當(dāng)時(shí)竟然沒想起來用concat()!

重新銘記一下:

${item.username.concat('-').concat(item.realname)}

05、 關(guān)于intern()

關(guān)于字符串的性能問題,我常在一些技術(shù)文章中看到這樣的建議:“如果一個(gè)字符串使用的頻率非常高,建議使用String.intern()將其緩存?!?/p>

但我并不建議你這么做,因?yàn)檫@個(gè)方法要顯式的調(diào)用,這樣很麻煩;況且,在代碼編寫階段,怎么可能知道哪個(gè)字符串使用頻率很高呢?

06、 關(guān)于StringUtils

據(jù)我的編程經(jīng)驗(yàn)來看,字符串的操作往往需要用到一個(gè)工具類,那就是org.apache.commons.lang3.StringUtils(null安全的,也就是說,StringUtils類的方法可以接受為null的字符串,但不會(huì)拋出NullPointerException)。

不過,我最常用的方法就那么幾個(gè):

方法等價(jià)
IsEmpty(String str)str == null or str.length == 0
isBlank(String str)str == null or str.length == 0 or str.trim().length == 0
join(Object[] arrey)把數(shù)組中的元素連接成一個(gè)字符串返回

上一篇:Java內(nèi)部類

下一篇:Java 數(shù)組,看這篇就夠了

微信搜索「沉默王二」公眾號(hào),關(guān)注后回復(fù)「免費(fèi)視頻」獲取 500G Java 高質(zhì)量教學(xué)視頻(已分門別類)。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

新聞標(biāo)題:JavaString,看這篇就夠了-創(chuàng)新互聯(lián)
地址分享:http://muchs.cn/article48/dshhep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、企業(yè)建站搜索引擎優(yōu)化、做網(wǎng)站、網(wǎng)站改版、網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)