????從概念上講苏揣,Java中字符串就是Unicode字符序列黄鳍。例如,"Hello"由H平匈、e框沟、l、l增炭、o 5個(gè)字符組成街望,Java沒(méi)有內(nèi)置的字符串類型,而是在標(biāo)準(zhǔn)Java類庫(kù)中提供了一個(gè)預(yù)定義類弟跑,很自然的叫做String灾前。每個(gè)雙引號(hào)括起來(lái)的字符串都是String類的一個(gè)實(shí)例。
一孟辑、創(chuàng)建String類
? ? String類型對(duì)象主要有兩種創(chuàng)建方式哎甲,第一種字面量賦值:String h = "hello"蔫敲;最常用的方式,如此方式炭玫,先查詢字符串常量池奈嘿,equlas判斷字符串常量池中有無(wú)為true的對(duì)象引用。沒(méi)有則在堆內(nèi)存中創(chuàng)建一個(gè)"hello"對(duì)象本體吞加,并在字符串常量池中添加裙犹,剛創(chuàng)建的堆內(nèi)存中"hello"對(duì)象引用。于此同時(shí)衔憨,如果再聲明一個(gè)String對(duì)象叶圃,String e = "hello";則不會(huì)再創(chuàng)建一個(gè)String對(duì)象践图,而是和變量h一樣獲得字符串常量區(qū)的該String對(duì)象的引用掺冠。
? ? 第二種,String h = new String("hello")码党;這種方式創(chuàng)建的String對(duì)象德崭,既有可能創(chuàng)建出兩個(gè)對(duì)象,也可能創(chuàng)建出一個(gè)對(duì)象揖盘。如果此時(shí)字符串常量區(qū)沒(méi)有值為"hello"對(duì)象眉厨,則會(huì)創(chuàng)建一個(gè)引用對(duì)象(1.6是永久復(fù)制一個(gè)String對(duì)象,1.7后改為復(fù)制實(shí)例的引用)兽狭,如果有則只創(chuàng)建一個(gè)在堆內(nèi)存中(String對(duì)象本體)憾股;
? ? String對(duì)象的值是不可變的,重新復(fù)制String變量只是改變其引用椭符,原對(duì)象沒(méi)有改變(1.8之前是char數(shù)組荔燎,1.8以后改為byte數(shù)組)
二销钝、== 和 equlas()
? ? 先回顧一下有咨,==和equls()的區(qū)別,==是比較二者值是否相等蒸健,用于基本類型是直接比較二者的值是否相等座享,用于對(duì)象則是比較二者的引用內(nèi)存地址是否相等。
? ? 那么在很多時(shí)候似忧,我們需要對(duì)String類型對(duì)象進(jìn)行比較渣叛,尤其是面試時(shí)經(jīng)常容易問(wèn)到相關(guān)字符串==比較的問(wèn)題,所以我們必須搞懂它盯捌。
? ? 面試中炒狙茫考的例子是:
? ? a變量賦值對(duì)象創(chuàng)建時(shí),因?yàn)闆](méi)有在字符串常量區(qū)里找到equals為true的String箫攀。所以在堆中創(chuàng)建一個(gè)"abc"對(duì)象肠牲,并且在非堆字符串常量池中創(chuàng)建對(duì)在堆中剛創(chuàng)建abc對(duì)象的引用,注意是引用靴跛,不是對(duì)象實(shí)體缀雳,然后把此引用賦給a變量。
? ? b變量賦值對(duì)象創(chuàng)建時(shí)梢睛,因?yàn)槭莕ew了一個(gè)String對(duì)象肥印,雖然值還是"abc",但是卻是在堆中新創(chuàng)建了一個(gè)對(duì)象绝葡,與上邊的不一樣深碱,有不同的內(nèi)存地址。
? ? a變量賦值對(duì)象創(chuàng)建后挤牛,堆中會(huì)創(chuàng)建一個(gè)"abc"對(duì)象莹痢,然后在非堆字符串常量池中創(chuàng)建其引用种蘸,然后b和c因?yàn)閑qulas到了相同對(duì)象墓赴,所以不創(chuàng)建新的對(duì)象,直接從字符串常量池中獲得"abc"的引用航瞭,因此==判斷時(shí)诫硕,此三個(gè)變量的值都相等,因?yàn)橹赶虻氖峭粋€(gè)對(duì)象刊侯。
? ? 還沒(méi)清楚的話章办,建議看這兩篇文章:
? ??java用這樣的方式生成字符串:String str = "Hello",到底有沒(méi)有在堆中創(chuàng)建對(duì)象滨彻? - 胖君的回答 - 知乎
????請(qǐng)別再拿“String s = new String("xyz");創(chuàng)建了多少個(gè)String實(shí)例”來(lái)面試了吧
? ? String的equals方法藕届,會(huì)比對(duì)兩個(gè)對(duì)象是否是一個(gè)對(duì)象,如果不是那么就逐一的檢查其byte數(shù)組其每一個(gè)數(shù)值是否相等亭饵,都相等返回true休偶。
? ? ? ? String類型的空串表示為""碱妆,長(zhǎng)度為0;空串為null昔驱,因?yàn)镾tring對(duì)象的變量也是引用類型疹尾,所以可以為其賦null值。因此判斷String類型有沒(méi)有值時(shí),需要檢查 是否為null和是否長(zhǎng)度為0纳本。
三睡雇、String的intern()方法
? ? intern方法,從1.7開(kāi)始饮醇,如果常量池中已經(jīng)有了這個(gè)字符串它抱,那么直接返回常量池中的它的引用,如果沒(méi)有就將該字符串的對(duì)象的引用保存到常量池中并返回朴艰。
? ? 知道了intern的功能了观蓄,那么它有什么用處?
????在上邊的例子中侮穿,第一行第二行并沒(méi)有創(chuàng)建"hello"字符串的實(shí)例,而第三行在常量池中創(chuàng)建了"hello"的引用毁嗦,因此c亲茅、d拿到了同一個(gè)對(duì)象的引用,所以相等狗准。
四袭祟、String類的常用API
? ? 只列舉幾個(gè)常用的方法,全部的可以查看官方文檔或String類源碼捞附。
? ? 1巾乳、int length()? 獲取字符串的長(zhǎng)度,基本上是最常用的方法
? ? 2鸟召、String trim() 獲取去除空格后的字符串
? ? 3胆绊、String[] split(String regex,int limit)?根據(jù)regex字符串對(duì)象值匹配分割字符串生成數(shù)組欧募,limit代表分割后數(shù)組最大長(zhǎng)度
? ? 4压状、String[] split(String regex) 根據(jù)regex字符串對(duì)象值匹配分割字符串生成數(shù)組
? ? 5、String[] substring(int beginIndex) 從beginIndex索引位置開(kāi)始截取槽片,去掉beginIndex之前的部分何缓。
? ? 6津肛、String[] substring(int beginIndex跳昼,int endIndex) 從beginIndex索引位置開(kāi)始截取到endIndex(不包括endIndex),去掉beginIndex之前的部分和endIndex與endIndex之后的部分背传。
? ? ? ?7剩盒、boolean equals(Object anObject) 傳入對(duì)象與當(dāng)前String對(duì)象為一個(gè)對(duì)象谷婆,或者值相等時(shí)返回true,反之false