深入理解String和StringBuilder

前言#

我偶爾會(huì)在問(wèn)答里面看一看誰(shuí)有問(wèn)題社搅,如果我知道就回答一下鸦难。今天偶然看到一個(gè)問(wèn)題标锄,去掉提問(wèn)的代碼部分,問(wèn)題就是:

String對(duì)象的intern()方法得到的對(duì)象譬涡,為什么與String對(duì)象有時(shí)候不相等闪幽?

我看到這個(gè)問(wèn)題,我也是懵逼了涡匀,今天就寫(xiě)個(gè)筆記復(fù)習(xí)一下沟使。

正文#

首先,這個(gè)String對(duì)象的intern()方法是干什么用的呢渊跋?看一下源碼的注釋?zhuān)?/p>

/**
* 英文注釋好長(zhǎng)腊嗡,這里就簡(jiǎn)單翻譯一下
* 返回一個(gè)這個(gè)String對(duì)象的權(quán)威代表(請(qǐng)注意着倾,這里返回的是代表,沒(méi)說(shuō)返回是自己)
* 有一個(gè)字符串池燕少,專(zhuān)門(mén)用來(lái)維持String對(duì)象卡者,當(dāng)intern方法被調(diào)用的時(shí)候,返回和他equals方法相同的String對(duì)象客们,如果沒(méi)有崇决,就把這個(gè)String添加到池中,再把這個(gè)String對(duì)象返回(也就是說(shuō)這個(gè)情況底挫,返回了自己)
* 
* s.intern() == t.intern()恒傻,只有在s.equals(t)等于true
*/     
public native String intern();

看來(lái)這個(gè)方法和equals關(guān)系密切,所以再看一下equals方法:

public boolean equals(Object anObject) {
    // 先判斷是否是同一個(gè)對(duì)象
        if (this == anObject) {
            return true;
        }
        // 判斷是否是String類(lèi)型
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = count;
            // 判斷字符串的長(zhǎng)度是否相等
            if (n == anotherString.count) {
                int i = 0;
                // 判斷每一個(gè)位置的字符是否相等
                while (n-- != 0) {
                    if (charAt(i) != anotherString.charAt(i))
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

equals判斷的僅僅的是字符串的內(nèi)容建邓,所以只要內(nèi)容相同盈厘,在字符串池中都不會(huì)重復(fù)添加。

結(jié)合我們已經(jīng)對(duì)字符串的了解官边,我們可以總結(jié)出一下幾點(diǎn):

1沸手、字符串池中,只包含唯一內(nèi)容的字符串注簿。
2契吉、字符串池,提供了相同字符串之間的復(fù)用機(jī)制诡渴,防止不同字符串創(chuàng)建多個(gè)對(duì)象捐晶。

這個(gè)時(shí)候突然想起來(lái)剛接觸Java時(shí)的一個(gè)面試題:

String s = "abc" 和 String s = new String("abc") 的區(qū)別

這個(gè)問(wèn)題大對(duì)數(shù)都能答對(duì):

String s = "abc" 是先使用字符串池中的abc對(duì)象,如果沒(méi)有創(chuàng)建abc并添加到字符串池中妄辩,這個(gè)邏輯和intern()方法是完全一樣的惑灵, 所以這種使用方法也是推薦的使用方法。

String s = new String("abc") 恩袱,一開(kāi)始的過(guò)程和第一種是一樣的泣棋,同樣是先從字符串池中獲取胶哲,然后根據(jù)情況添加或者返回畔塔。但是new操作符,會(huì)返回一個(gè)新的String對(duì)象鸯屿,也就是說(shuō)澈吨,返回的String對(duì)象并不是abc。但是這種方法會(huì)出現(xiàn)內(nèi)存的浪費(fèi)寄摆,所以并不推薦使用谅辣。

為了驗(yàn)證我們的想法,我們運(yùn)行一個(gè)小demo:

public class Main {
    
    public static void main(String[] args){
        // 注意這里通過(guò)創(chuàng)建StringBuilder婶恼,已經(jīng)創(chuàng)建了111桑阶,并加入到字符串池
        String s1 = new StringBuilder("111").toString();
    // 這里還是通過(guò)相同的方式柏副,看看是否返回了跟s1相同的對(duì)象
        String s2 = new StringBuilder("111").toString();
        // 直接從字符串池中得到對(duì)象
        String s3 = "111";
        String s4 = "111";
       
        System.out.println(s1.equals(s2));
        System.out.println(s1 == s2);

        System.out.println(s3.equals(s4));
        System.out.println(s3 == s4);
    }

}

首先我們使用了兩個(gè)StringBuilder來(lái)拼接字符串,看看得到的結(jié)果蚣录,然后直接從字符串池中去取割择,看看得到是不是同一個(gè)對(duì)象。

true
false
true
true

第一個(gè)結(jié)果是s1.equals(s2) =true萎河,這個(gè)沒(méi)有疑問(wèn)荔泳,對(duì)比內(nèi)容必然是相同的。
第二個(gè)結(jié)果是s1 == s2 得到false虐杯,說(shuō)明是s1和s2是相同內(nèi)容的不同對(duì)象玛歌。

為什么不是相同對(duì)象呢?看一下StringBuilder的toString()方法:

@Override
public String toString() {
        // Create a copy, don't share the array
   return new String(value, 0, count);
}

竟然是一個(gè)new String擎椰,怪不得對(duì)象是不相同的支子。

第三個(gè)結(jié)果s3.equals(s4) = true, 這個(gè)沒(méi)有疑問(wèn)确憨,對(duì)比內(nèi)容必然是相同的译荞。
第四個(gè)結(jié)果s3 == s4,一樣是true休弃,說(shuō)明得到確實(shí)是相同的對(duì)象吞歼。

總結(jié)#

有了剛才的驗(yàn)證,我們基本上可以這么理解:

"abc" , 我們可以看做是單例模式塔猾,這個(gè)abc只創(chuàng)建一次篙骡,可以復(fù)用。
例如 String s = "abc", StringBuilder.append("abc")丈甸,實(shí)際上使用的都是同一個(gè)字符串對(duì)象糯俗。

并且我們知道了平時(shí)使用字符串的幾個(gè)小細(xì)節(jié):

1、String的equals()方法判斷的內(nèi)容相同睦擂,不是判斷是否是相同對(duì)象得湘。
2、StringBuilder的toString()方法顿仇,會(huì)創(chuàng)建新的字符串對(duì)象并返回淘正,這個(gè)還是有優(yōu)化空間的。

我們把之前學(xué)到的內(nèi)容又重新復(fù)習(xí)了一遍臼闻,還找到了StringBuilder性能可以優(yōu)化的地方鸿吆,這次復(fù)習(xí)的收獲還是非常驚喜的,最后貼出那個(gè)朋友提出的問(wèn)題:

public static void main(String[] argv){
String a = new StringBuilder("aa").append("計(jì)算機(jī)").toString();
System.out.println(a.intern()==a);
String b = new StringBuilder().append("計(jì)算機(jī)").toString();
System.out.println(b.intern()==b);
String c = new String("dsd");
System.out.println(c.intern()==c);
}
為何結(jié)果是
true
false
false
而不是
false
false
fasle
?

這個(gè)問(wèn)題你能夠幫他解答嗎述呐?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惩淳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乓搬,更是在濱河造成了極大的恐慌思犁,老刑警劉巖代虾,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異激蹲,居然都是意外死亡褐着,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)托呕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)含蓉,“玉大人,你說(shuō)我怎么就攤上這事项郊∠诳郏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵着降,是天一觀的道長(zhǎng)差油。 經(jīng)常有香客問(wèn)我,道長(zhǎng)任洞,這世上最難降的妖魔是什么蓄喇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮交掏,結(jié)果婚禮上妆偏,老公的妹妹穿的比我還像新娘。我一直安慰自己盅弛,他們只是感情好钱骂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著挪鹏,像睡著了一般见秽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上讨盒,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天解取,我揣著相機(jī)與錄音,去河邊找鬼返顺。 笑死禀苦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的创南。 我是一名探鬼主播伦忠,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼省核,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稿辙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起气忠,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤邻储,失蹤者是張志新(化名)和其女友劉穎赋咽,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吨娜,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脓匿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宦赠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陪毡。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖勾扭,靈堂內(nèi)的尸體忽然破棺而出毡琉,到底是詐尸還是另有隱情,我是刑警寧澤妙色,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布桅滋,位于F島的核電站,受9級(jí)特大地震影響身辨,放射性物質(zhì)發(fā)生泄漏丐谋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一煌珊、第九天 我趴在偏房一處隱蔽的房頂上張望号俐。 院中可真熱鬧,春花似錦定庵、人聲如沸萧落。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)找岖。三九已至,卻和暖如春敛滋,著一層夾襖步出監(jiān)牢的瞬間许布,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工绎晃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜜唾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓庶艾,卻偏偏與公主長(zhǎng)得像袁余,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咱揍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法颖榜,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法掩完,異常的語(yǔ)法噪漾,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,597評(píng)論 18 399
  • 一、String 類(lèi) 1且蓬、定義: 1欣硼、從概念上講,java字符串就是Unicode字符序列恶阴。每個(gè)用雙引號(hào)括起來(lái)的字...
    玉圣閱讀 1,562評(píng)論 0 1
  • Tip:筆者馬上畢業(yè)了诈胜,準(zhǔn)備開(kāi)始 Java 的進(jìn)階學(xué)習(xí)計(jì)劃。于是打算先從 String 類(lèi)的源碼分析入手冯事,作為后面...
    石先閱讀 12,000評(píng)論 16 58
  • 糖尿病分為一型和二型耘斩,臨床上絕大多數(shù)糖尿病患者都屬于二型糖尿病,到今天為止桅咆,幾乎所有的醫(yī)學(xué)論著括授,醫(yī)生和營(yíng)養(yǎng)師都都在...
    花語(yǔ)88閱讀 281評(píng)論 0 0
  • 笑與淚最后都會(huì)連帶著冰冷的身軀臥進(jìn)沃土之中。在那個(gè)萬(wàn)念俱灰的封閉逼仄的空間里岩饼,臭蟲(chóng)不會(huì)鉆進(jìn)我們的大腦荚虚,窺視我...
    取個(gè)帥氣的昵稱拔閱讀 187評(píng)論 0 0