面試題系列第1篇:說說==和equals的區(qū)別?你的回答可能是錯(cuò)誤的

最近準(zhǔn)備再刷刷面試題忍抽,將面試題中比較經(jīng)典和核心的內(nèi)容寫成系列文章發(fā)表在公眾號中八孝,鞏固基礎(chǔ)知識,分享給大家鸠项,歡迎大家持續(xù)關(guān)注【程序新視界】干跛。下面是本系列第1篇。

大多數(shù)面試的第一題不是讓說說面向?qū)ο笏畎恚褪顷P(guān)于字符的楼入。本篇文章就從各方面來聊聊“==和equals的區(qū)別”哥捕。

概念上的區(qū)別

針對字符串(注意僅限字符串)的比較,==和equals的區(qū)別有以下兩點(diǎn):

(1)"=="是判斷兩個(gè)變量或?qū)嵗遣皇侵赶蛲粋€(gè)內(nèi)存空間嘉熊。

(2)"equals"是判斷兩個(gè)變量或?qū)嵗赶虻膬?nèi)存空間的值是不是相同遥赚。

單純從抽象的概念來看上面的描述還是比較晦澀難懂的。為了講解清楚上面的概念阐肤,我們先來簡單了解一下JVM內(nèi)存分配的知識凫佛。

創(chuàng)建對象的內(nèi)存分配

在JVM中,內(nèi)存分為堆內(nèi)存和棧內(nèi)存孕惜。通常情況愧薛,當(dāng)我們通過new關(guān)鍵字創(chuàng)建一個(gè)對象時(shí),就會調(diào)用對象的構(gòu)造函數(shù)來開辟空間衫画,將對象數(shù)據(jù)存儲到堆內(nèi)存中厚满,與此同時(shí)在棧內(nèi)存中生成對應(yīng)的引用。

String str = new String("程序新視界");

上述代碼中碧磅,真實(shí)的String對象存儲在堆內(nèi)存中碘箍,str變量僅持有指向該對象的引用地址。當(dāng)在后續(xù)代碼調(diào)用時(shí)鲸郊,用的都是棧內(nèi)存中的引用(str指向的地址)丰榴。

String是如何實(shí)現(xiàn)equals方法的

了解了上面的概念,我們再來看看String中是如何實(shí)現(xiàn)equals方法的秆撮。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

上面的代碼分兩部分四濒。第一部分,直接通過“==”進(jìn)行比較职辨,我們已經(jīng)知道這是比較對象的引用地址是否相等盗蟆。也就是說如果兩個(gè)對象的引用地址相同,那么它們便是相等的舒裤。

第二部分代碼喳资,判斷傳入的對象是否為String對象,如果是String對象并且兩個(gè)String對象的值的char[]數(shù)組中的每個(gè)元素值都相等腾供,則它們便是相等的仆邓。

看完了上述代碼,大家可能就明白了在講述它們的區(qū)別時(shí)為什么要添加上“注意僅限字符串”的備注了伴鳖。String的equals方法之所以比較的是值节值,是因?yàn)樗貙懥薳quals方法。

匯總一下榜聂,針對String的比較可以用下面一張圖來展示:

面試String

我們知道Java中所有的類都繼承自O(shè)bject對象搞疗,而Object對象中也定義了equals方法:

public boolean equals(Object obj) {
    return (this == obj);
}

我們看到了什么?Object的equals方法比較的竟然也是引用地址须肆!所以匿乃,如果單單的說“==”比較的是引用脐往,equals比較的是引用對應(yīng)的值,是錯(cuò)誤的扳埂!這里要限定于String類這個(gè)范圍业簿。

當(dāng)我們定義一個(gè)類時(shí),如果未重寫equals方法時(shí)便使用的是Object默認(rèn)的equals方法阳懂。如果重寫該方法梅尤,則按照重寫的方法實(shí)現(xiàn)進(jìn)行比較,String的equals方法便是重寫的示例之一岩调。

特殊的String定義

String除了通過new的形式進(jìn)行定義巷燥,還可以通過等號賦值的形式:

String str = "程序新視界";

這是一種非常特殊的形式,不需要new就可以產(chǎn)生對象号枕,和new有本質(zhì)的區(qū)別缰揪。這種形式的賦值在java中叫直接量,它是存在于常量池中葱淳,而不是像new一樣存放在堆中钝腺。

當(dāng)聲明這樣一個(gè)字符串時(shí),JVM會在常量池中先查找有沒有對應(yīng)值的對象赞厕。如果有艳狐,把它賦給當(dāng)前引用,即原來的引用和現(xiàn)在的引用指向了同一對象皿桑。如果沒有毫目,則在常量池中新創(chuàng)建一個(gè)對象。以這形式聲明的字符串诲侮,只要值相等镀虐,任何多個(gè)引用都指向同一對象。

對照new形式創(chuàng)建String對象和創(chuàng)建其他對象一樣沟绪,每次調(diào)用就產(chǎn)生一個(gè)新的對象刮便。

示例驗(yàn)證

下面以具體的實(shí)例來驗(yàn)證以上結(jié)論。同時(shí)近零,這些驗(yàn)證的實(shí)例也有可能是面試題的考點(diǎn)內(nèi)容诺核。

String x = "程序新視界";
String y = "程序新視界";
String z = new String("程序新視界");

System.out.println(x == y); // true
System.out.println(x == z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

第一行,因?yàn)槎际峭ㄟ^賦值創(chuàng)建對象久信,當(dāng)內(nèi)存中已經(jīng)存在x對應(yīng)的對象,賦值y對象時(shí)直接將引用指向原有對象漓摩。因此相等裙士。

第二行,因?yàn)閦通過new形式創(chuàng)建管毙,會創(chuàng)建新的對象腿椎,此處比較的是兩個(gè)對象的引用地址桌硫,因此不相等。

第三啃炸、四行铆隘,均比較字符串的實(shí)際值,因此相等南用。

下面再看一下未重寫equals方法的對象比較膀钠。對應(yīng)的實(shí)體類定義和單元測試方法如下:

@Test
public void testObject(){
    Person p1 = new Person("Tom");
    Person p2 = new Person("Tom");

    System.out.println(p1.equals(p2));
}

class Person{

    public Person(String name){
        this.name = name;
    }
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

執(zhí)行上述方法,打印結(jié)果為false裹虫。

通過以上兩個(gè)實(shí)例肿嘲,均驗(yàn)證了我們上面所講的理論。

小結(jié)

經(jīng)過上面的分析筑公,理解了底層的邏輯雳窟,想必大家再遇到類似面試題時(shí)便能準(zhǔn)確回答。

簡單的說通過等號比較的是引用匣屡,通過equals比較的是值封救。從嚴(yán)格意義上來說是錯(cuò)誤的。通過JVM對象的存儲形式以及重寫equals方法等底層實(shí)現(xiàn)原理來進(jìn)行解答才能體現(xiàn)你的實(shí)力捣作,而不是死記硬背兴泥。

下篇文章,我們來講講new String的形式創(chuàng)建了幾個(gè)對象及底層邏輯虾宇,歡迎持續(xù)關(guān)注搓彻。


程序新視界:精彩和成長都不容錯(cuò)過!

程序新視界-微信公眾號
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘱朽,一起剝皮案震驚了整個(gè)濱河市旭贬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搪泳,老刑警劉巖稀轨,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岸军,居然都是意外死亡奋刽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門艰赞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佣谐,“玉大人,你說我怎么就攤上這事方妖∠粱辏” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長雌澄。 經(jīng)常有香客問我斋泄,道長,這世上最難降的妖魔是什么镐牺? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任炫掐,我火速辦了婚禮,結(jié)果婚禮上睬涧,老公的妹妹穿的比我還像新娘募胃。我一直安慰自己,他們只是感情好宙地,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布摔认。 她就那樣靜靜地躺著,像睡著了一般宅粥。 火紅的嫁衣襯著肌膚如雪参袱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天秽梅,我揣著相機(jī)與錄音抹蚀,去河邊找鬼。 笑死企垦,一個(gè)胖子當(dāng)著我的面吹牛环壤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钞诡,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼郑现,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了荧降?” 一聲冷哼從身側(cè)響起接箫,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朵诫,沒想到半個(gè)月后辛友,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剪返,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年废累,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脱盲。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邑滨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宾毒,到底是詐尸還是另有隱情驼修,我是刑警寧澤殿遂,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布诈铛,位于F島的核電站乙各,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏幢竹。R本人自食惡果不足惜耳峦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焕毫。 院中可真熱鬧蹲坷,春花似錦、人聲如沸邑飒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疙咸。三九已至县匠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間撒轮,已是汗流浹背乞旦。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留题山,地道東北人兰粉。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像顶瞳,于是被迫代替她去往敵國和親玖姑。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345