Java學(xué)習(xí)筆記(3)—— String類詳解

前言

因為沒有成功地為IDEA配上反編譯工具许赃,所以自己下載了一個XJad工具子眶,背景是白色的,所以忍著強迫癥硬是把IDEA的主體也給換成白色了歼冰,感覺為了這篇文章付出了諸多啊....

字符串簡介

《Thinging in Java》中有一句話:可以證明美尸,字符串操作是計算機程序設(shè)計中最常見的行為冤议。

把多個字符按照一定的順序排列起來,就叫字符串(就像羊肉串一樣师坎,串起來的)恕酸,具體是怎么排列的,你可以跟進String的源代碼去看一下胯陋,會發(fā)現(xiàn)它其實內(nèi)部維護的是一個char類型的數(shù)組:

String類內(nèi)部維護的是一個char數(shù)組
// 也就是說
String str = "ABCD";      // 定義一個字符串對象蕊温,其實等價于:
char[] cr = new char[]{'A','B','C','D'};

字符串的分類

其實說起來會有些別扭,為什么字符串會有分類這種東西遏乔。了解的朋友可能會知道字符串的操作除了String义矛,還有StringBuffer和StringBuilder(區(qū)別我們在下面來說)

不可變的字符串

String是一個奇葩。

String對象不可變盟萨,也就是說當(dāng)對象創(chuàng)建完畢之后凉翻,該對象的內(nèi)容(字符序列)是不允許改變的,如果內(nèi)容改變則會創(chuàng)建一個新的String對象捻激,返回到原地址中制轰。

細(xì)心的朋友也許會發(fā)現(xiàn)前计,String類維護的char數(shù)組不僅被final所修飾,并且查看JDK源碼你就會發(fā)現(xiàn)垃杖,String類中每一個看起來會修改String值得方法男杈,實際上都是創(chuàng)建了一個全新的String對象,以包含修改后的字符串對象调俘。而最初的String對象則絲毫未動伶棒。我們可以簡單的來看一個實例(從替換操作中就能明顯看出):

String類中的replace方法

replace方法就是替換字符串中的內(nèi)容,如果替換之后跟原來的字符串相同則返回this彩库,如果不相同則new一個新的對象返回肤无。這明顯體現(xiàn)了內(nèi)容改變則返回新對象而不是直接修改String對象的值。

表面的錯覺

關(guān)于String對象是否可變骇钦,有些操作確實會給人錯覺舅锄,先來看一段程序:

一個例子

從結(jié)果來看,s1的值最初是“A”司忱,經(jīng)過賦值以后,變成了“C”,經(jīng)過字符串連接運算并賦值以后畴蹭,變成了“BC”坦仍。String對象的內(nèi)容真的改變了嗎?實際上叨襟,這只是錯覺而已繁扎。有疑惑的朋友可以去看我的上一篇筆記,你就能知道:

String對象“A”糊闽,“B”梳玫,“C”在全程中都沒有任何改變,改變的只是引用s1所指向的內(nèi)容右犹,也就是s1的值提澎。

String對象的創(chuàng)建

有兩種方式:

// 第一種:直接賦一個字面量
String str1 = "ABCD";
// 第二種:通過構(gòu)造器創(chuàng)建
String str2 = new String("ABCD");

那么這兩種方式有什么不同呢?這里可能會涉及到一個面試題:

上述的兩種方法分別創(chuàng)建了幾個String對象念链?

回答這個問題也特別簡單盼忌,首先你需要直到JVM的內(nèi)存模型是怎樣的,在上一篇筆記中也有簡單提到掂墓,這里需要補充的是:常量池(專門存儲常量的地方谦纱,都指的是方法區(qū)中)分為編譯常量池(不研究,存儲字節(jié)碼的相關(guān)信息)和運行常量池(存儲常量數(shù)據(jù))君编。

先來看一張結(jié)果圖:


結(jié)果圖
  • 當(dāng)執(zhí)行第一句話的時候跨嘉,會在常量池中添加一個新的ABCD字符,str1指向常量池的ABCD
  • 當(dāng)執(zhí)行第二句話的時候吃嘿,因為有new操作符祠乃,所以會在堆空間新開辟一塊空間用來存儲新的String對象梦重,因為此時常量池中已經(jīng)有了ABCD字符,所以堆中的String對象指向常量池中的ABCD跳纳,而str2則指向堆空間中的String對象忍饰。

所以結(jié)論:
String str1 = "ABCD";
最多創(chuàng)建一個String對象,最少不創(chuàng)建String對象.如果常量池中,存在”ABCD”,那么str1直接引用,此時不創(chuàng)建String對象.否則,先在常量池先創(chuàng)建”ABCD”內(nèi)存空間,再引用.
String str2 = new String("ABCD");
最多創(chuàng)建兩個String對象,至少創(chuàng)建一個String對象寺庄。new關(guān)鍵字絕對會在堆空間創(chuàng)建一塊新的內(nèi)存區(qū)域艾蓝,所以至少創(chuàng)建一個String對象。

String對象的空值

一種是表示引用為空(null)的空值:

String str1 = null;  // 沒有初始化斗塘,沒有分配內(nèi)存空間

另外一種表示內(nèi)容為空的空值:

String str2 = ";  // 分配有內(nèi)存空間赢织,有內(nèi)容。

所以當(dāng)你需要判斷字符串是否為空的時候馍盟,實際上應(yīng)該這樣:


判斷字符串非空

字符串的比較

字符串的比較

從上圖可以明顯看出于置,使用“==”,只能比較引用的內(nèi)存地址是否相同贞岭,而使用“equals”方法八毯,則比較的是字符串的內(nèi)容。

我們可以跟到String類的equals方法:


String類的equals方法

“+”號是怎么來連接字符串的

先來直接看一個簡單的例子瞄桨,程序中創(chuàng)建了三個String對象话速,str是hello和wrold兩個字符串連接賦值后的對象,程序的結(jié)果很明顯芯侥,但我們關(guān)心的是泊交,hello和world是怎樣連接起來的呢?

先來看一個例子

我們在XJad(Java反編譯程序柱查,把生成的class反編譯成java)中打開剛剛生成的class文件會發(fā)現(xiàn):

反編譯的結(jié)果

編譯器自動引入了一個java.lang.StringBuilder類廓俭。雖然我們在源代碼中并沒有使用StringBuilder類,但是編譯器卻自作主張地使用了它唉工,因為它更高效研乒。

在這個例子中,編譯器創(chuàng)建了一個StringBuilde對象酵紫,用以構(gòu)造最終的String告嘲,并為每個字符串調(diào)用了一次StringBuilderappend()方法,總計兩次奖地。最后調(diào)用toString()生成結(jié)果橄唬。這是編譯器自動優(yōu)化的結(jié)果,包括自動生成的Tester()無參數(shù)默認(rèn)的構(gòu)造函數(shù)也是参歹。

現(xiàn)在仰楚,你也許會覺得可以隨意使用String對象,反正編譯器會為你自動地優(yōu)化性能∩纾可是在這之前侨嘀,我們先要看看編譯器究竟能給我們優(yōu)化到什么程度(下面再詳細(xì)介紹StringBuilder)。

可變的字符串

StringBuilder/StringBuffer:當(dāng)對象創(chuàng)建完畢之后捂襟,該對象的內(nèi)容可以發(fā)生改變咬腕,當(dāng)內(nèi)容發(fā)生改變的時候,對象保持不變葬荷。

接著上面的問題涨共,我們繼續(xù)來看一個例子:

程序和程序的結(jié)果

程序的結(jié)果顯而易見,我們來看看反編譯之后的代碼:
反編譯之后的代碼

可以看到宠漩,對比兩個對象举反,后者的循環(huán)部分的代碼更簡短、更簡單扒吁,而且它只生成了一個StringBuilder對象火鼻。

結(jié)論是:如果字符串操作比較簡單,那就可以信賴編譯器雕崩,它會為你合理地構(gòu)造最終的字符串結(jié)果魁索。但如果你還使用循環(huán),多次地改變字符串的內(nèi)容盼铁,那就更適合StringBuilder對象蛾默。

但是如果你想要走捷徑,例如append(a+":"+c)捉貌,則編譯器就會調(diào)入陷阱,從而為你另外創(chuàng)建一個StringBuilder對象處理括號內(nèi)的字符串操作冬念。

編譯器陷阱

String對象的比較

StringBuilder是Java SE5引入的趁窃,在這之前Java用的是StringBuffer。后者線程安全(只需要了解急前,該對象方法中所有的方法都是用了synchronized修飾符)醒陆,因此開銷也會大。有沒有用synchronized修飾符裆针,就是這兩者唯一的區(qū)別刨摩。我們可以簡單地來比較一下這三個String對象在拼接字符串中的性能:

創(chuàng)建好三個方法,分別測試三個類型的對象的拼接效率:


測試拼接效率

最后在main方法中測試

面試題

最后再有一個String的面試題:

說說下面的String對象世吨,彼此之間是否相等澡刹?

面試題

如果你自己寫幾個判斷相等的語句,分別判斷str1和另外五個是否相等耘婚,則會發(fā)現(xiàn):
str1和str2/str3相等罢浇,和另外幾個都不相等。我們先來看一下反編譯之后的代碼:

編譯之后的代碼(存在編譯優(yōu)化)

知識點(純干貨):

  • 單獨使用""引號創(chuàng)建的字符串都是直接量,編譯期就已經(jīng)確定存儲到常量池中;
  • 使用new String("")創(chuàng)建的對象會存儲到堆內(nèi)存中,是運行期才創(chuàng)建嚷闭;
  • 使用只包含直接量的字符串連接符如"aa" + "bb"創(chuàng)建的也是直接量編譯期就能確定,已經(jīng)確定存儲到常量池中(str2和str3)攒岛;
  • 使用包含String直接量(無final修飾符)的字符串表達(dá)式(如"aa" + s1)創(chuàng)建的對象是運行期才創(chuàng)建的,存儲在堆中;
  • 通過變量/調(diào)用方法去連接字符串,都只能在運行時期才能確定變量的值和方法的返回值,不存在編譯優(yōu)化操作.

文章結(jié)尾

其實還想寫關(guān)于正則表達(dá)的東西的胞锰,還是改天找時間另外研究研究寫一篇像樣的吧灾锯。關(guān)于String的操作,就簡單給一下圖吧嗅榕,感興趣也可以自己百度或者跟蹤進源代碼里面去看顺饮,這里就不細(xì)說了:

String類中常用的方法

參考資料:


歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處誊册!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號:wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末领突,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子案怯,更是在濱河造成了極大的恐慌君旦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘲碱,死亡現(xiàn)場離奇詭異金砍,居然都是意外死亡,警方通過查閱死者的電腦和手機麦锯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門恕稠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扶欣,你說我怎么就攤上這事鹅巍。” “怎么了料祠?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵骆捧,是天一觀的道長。 經(jīng)常有香客問我髓绽,道長敛苇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任顺呕,我火速辦了婚禮枫攀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘株茶。我一直安慰自己来涨,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布启盛。 她就那樣靜靜地躺著扫夜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笤闯,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天堕阔,我揣著相機與錄音,去河邊找鬼颗味。 笑死超陆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浦马。 我是一名探鬼主播时呀,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晶默!你這毒婦竟也來了谨娜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤磺陡,失蹤者是張志新(化名)和其女友劉穎趴梢,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體币他,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡坞靶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝴悉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彰阴。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拍冠,靈堂內(nèi)的尸體忽然破棺而出尿这,到底是詐尸還是另有隱情,我是刑警寧澤庆杜,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布妻味,位于F島的核電站,受9級特大地震影響欣福,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜焦履,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一拓劝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嘉裤,春花似錦郑临、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春躺翻,著一層夾襖步出監(jiān)牢的瞬間丧叽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工公你, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留踊淳,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓陕靠,卻偏偏與公主長得像迂尝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子剪芥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容