callablestatement.setstring会不会将字符串trim_Java String:重要到别人只能当老二的字符串类
字符串,是Java中最重要的類。這句肯定的推斷不是Java之父詹姆斯·高斯林說的,而是沉默王二說的,因此你不必懷疑它的準(zhǔn)確性。
關(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 Stringimplements java.io.Serializable, Comparable<String>, CharSequence { }可以發(fā)現(xiàn),String類是final類型的,因此不能被繼承。
如果類可以被繼承,那么就會(huì)破壞類的不可變性機(jī)制。因?yàn)樽宇惪梢愿采w父類的方法,并且可以改變父類的成員變量值,一旦子類以父類的形式出現(xiàn)時(shí),就不能保證類是不可變的。
String類的不可變性有什么好處呢?
1)作為HashMap的鍵。
因?yàn)樽址遣豢勺兊?#xff0c;因此它在創(chuàng)建的時(shí)候哈希碼(hash code)就計(jì)算好了。這也就意味著每次在使用一個(gè)字符串的哈希碼的時(shí)候不用重新計(jì)算一次,這樣更加高效,很適合作為HashMap中的鍵。
2)線程安全。
同一個(gè)字符串對(duì)象可以被多個(gè)線程共享,如果訪問頻繁的話,可以省略同步和鎖等待的時(shí)間,從而提升性能。
3)字符串常量池的需要。
稍后介紹。
特別要注意的是,String類的所有方法都沒有改變字符串本身的值,都是返回了一個(gè)新的對(duì)象。
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); // 輸出trueString 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 = "u5A0Cu5910u7CAF"; String s1 = "u941Cu5B29u7C29"; 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("u5A0Cu5910u7CAFu941Cu5B29u7C29").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()將其緩存。”
但我并不建議你這么做,因?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 == nullstr.length == 0`isBlank(String str)`str == nullstr.length == 0str.trim().length == 0`join(Object[] arrey)把數(shù)組中的元素連接成一個(gè)字符串返回
推薦閱讀:
Java異常處理:給程序罩一層保險(xiǎn)
Java集合類:我其實(shí)沒那么簡(jiǎn)單
總結(jié)
以上是生活随笔為你收集整理的callablestatement.setstring会不会将字符串trim_Java String:重要到别人只能当老二的字符串类的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下代码写错了怎么更改_AWS全
- 下一篇: 谷歌浏览器修复一键修复_谷歌发布Chro