Java中==和equals的區(qū)別卓研,equals和hashCode的區(qū)別

在java中:

==是運(yùn)算符,用于比較兩個變量是否相等睹簇。

equals奏赘,是Objec類的方法,用于比較兩個對象是否相等太惠,默認(rèn)Object類的equals方法是比較兩個對象的地址磨淌,跟==的結(jié)果一樣。Object的equals方法如下:

public boolean equals(Object obj) {

return (this == obj);

}

hashCode也是Object類的一個方法凿渊。返回一個離散的int型整數(shù)梁只。在集合類操作中使用,為了提高查詢速度埃脏。(HashMap搪锣,HashSet等)

有了這三個基礎(chǔ)概念,區(qū)別就簡單了彩掐。網(wǎng)上有很多构舟,匯總一下:

java中的數(shù)據(jù)類型,可分為兩類:

1.基本數(shù)據(jù)類型堵幽,也稱原始數(shù)據(jù)類型狗超。byte,short,char,int,long,float,double,boolean

他們之間的比較,應(yīng)用雙等號(==),比較的是他們的值朴下。

2.復(fù)合數(shù)據(jù)類型(類)

當(dāng)他們用(==)進(jìn)行比較的時候努咐,比較的是他們在內(nèi)存中的存放地址,所以殴胧,除非是同一個new出來的對象渗稍,他們的比較后的結(jié)果為true,否則比較后結(jié)果為false。 JAVA當(dāng)中所有的類都是繼承于Object這個基類的竿屹,在Object中的基類中定義了一個equals的方法音五,這個方法的初始行為是比較對象的內(nèi)存地 址,但在一些類庫當(dāng)中這個方法被覆蓋掉了羔沙,如String,Integer,Date在這些類當(dāng)中equals有其自身的實(shí)現(xiàn)躺涝,而不再是比較類在堆內(nèi)存中的存放地址了。

對于復(fù)合數(shù)據(jù)類型之間進(jìn)行equals比較扼雏,在沒有覆寫equals方法的情況下坚嗜,他們之間的比較還是基于他們在內(nèi)存中的存放位置的地址值的,因?yàn)镺bject的equals方法也是用雙等號(==)進(jìn)行比較的诗充,所以比較后的結(jié)果跟雙等號(==)的結(jié)果相同苍蔬。

如果兩個對象根據(jù)equals()方法比較是相等的,那么調(diào)用這兩個對象中任意一個對象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果蝴蜓。

如果兩個對象根據(jù)equals()方法比較是不相等的碟绑,那么調(diào)用這兩個對象中任意一個對象的hashCode方法,則不一定要產(chǎn)生相同的整數(shù)結(jié)果

從而在集合操作的時候有如下規(guī)則:

將對象放入到集合中時茎匠,首先判斷要放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等格仲,如果不相等直接將該對象放入集合中。如果hashcode值相等诵冒,然后再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等凯肋,如果equals判斷不相等,直接將該元素放入到集合中汽馋,否則不放入侮东。

回過來說get的時候,HashMap也先調(diào)key.hashCode()算出數(shù)組下標(biāo)豹芯,然后看equals如果是true就是找到了悄雅,所以就涉及了equals。

《Effective Java》書中有兩條是關(guān)于equals和hashCode的:

覆蓋equals時需要遵守的通用約定:

覆蓋equals方法看起來似乎很簡單铁蹈,但是如果覆蓋不當(dāng)會導(dǎo)致錯誤宽闲,并且后果相當(dāng)嚴(yán)重∧痉欤《Effective Java》一書中提到“最容易避免這類問題的辦法就是不覆蓋equals方法”便锨,這句話貌似很搞笑,其實(shí)想想也不無道理我碟,其實(shí)在這種情況下,類的每個實(shí)例都只與它自身相等姚建。如果滿足了以下任何一個條件矫俺,這就正是所期望的結(jié)果:

類的每個實(shí)例本質(zhì)上都是唯一的。對于代表活動實(shí)體而不是值的類來說卻是如此,例如Thread厘托。Object提供的equals實(shí)現(xiàn)對于這些類來說正是正確的行為友雳。

不關(guān)心類是否提供了“邏輯相等”的測試功能。假如Random覆蓋了equals铅匹,以檢查兩個Random實(shí)例是否產(chǎn)生相同的隨機(jī)數(shù)序列押赊,但是設(shè)計者并不認(rèn)為客戶需要或者期望這樣的功能。在這樣的情況下包斑,從Object繼承得到的equals實(shí)現(xiàn)已經(jīng)足夠了流礁。

超類已經(jīng)覆蓋了equals,從超類繼承過來的行為對于子類也是合適的罗丰。大多數(shù)的Set實(shí)現(xiàn)都從AbstractSet繼承equals實(shí)現(xiàn)神帅,List實(shí)現(xiàn)從AbstractList繼承equals實(shí)現(xiàn),Map實(shí)現(xiàn)從AbstractMap繼承equals實(shí)現(xiàn)萌抵。

類是私有的或者是包級私有的找御,可以確定它的equals方法永遠(yuǎn)不會被調(diào)用。在這種情況下绍填,無疑是應(yīng)該覆蓋equals方法的霎桅,以防止它被意外調(diào)用:

@Override

public boolean equals(Object o){

throw new AssertionError(); //Method is never called

}

在覆蓋equals方法的時候,你必須要遵守它的通用約定讨永。下面是約定的內(nèi)容哆档,來自O(shè)bject的規(guī)范[JavaSE6]

自反性。對于任何非null的引用值x住闯,x.equals(x)必須返回true瓜浸。

對稱性。對于任何非null的引用值x和y比原,當(dāng)且僅當(dāng)y.equals(x)返回true時插佛,x.equals(y)必須返回true

傳遞性。對于任何非null的引用值x量窘、y和z雇寇,如果x.equals(y)返回true,并且y.equals(z)也返回true蚌铜,那么x.equals(z)也必須返回true锨侯。

一致性。對于任何非null的引用值x和y冬殃,只要equals的比較操作在對象中所用的信息沒有被修改囚痴,多次調(diào)用該x.equals(y)就會一直地返回true,或者一致地返回false审葬。

對于任何非null的引用值x深滚,x.equals(null)必須返回false奕谭。

結(jié)合以上要求,得出了以下實(shí)現(xiàn)高質(zhì)量equals方法的訣竅:

1.使用==符號檢查“參數(shù)是否為這個對象的引用”痴荐。如果是血柳,則返回true。這只不過是一種性能優(yōu)化生兆,如果比較操作有可能很昂貴难捌,就值得這么做。

2.使用instanceof操作符檢查“參數(shù)是否為正確的類型”鸦难。如果不是根吁,則返回false。一般來說明刷,所謂“正確的類型”是指equals方法所在的那個類婴栽。

3.把參數(shù)轉(zhuǎn)換成正確的類型。因?yàn)檗D(zhuǎn)換之前進(jìn)行過instanceof測試辈末,所以確保會成功愚争。

4.對于該類中的每個“關(guān)鍵”域,檢查參數(shù)中的域是否與該對象中對應(yīng)的域相匹配挤聘。如果這些測試全部成功轰枝,則返回true;否則返回false。

5.當(dāng)編寫完成了equals方法之后组去,檢查“對稱性”鞍陨、“傳遞性”、“一致性”从隆。

覆蓋equals時總要覆蓋hashCode

一個很常見的錯誤根源在于沒有覆蓋hashCode方法诚撵。在每個覆蓋了equals方法的類中,也必須覆蓋hashCode方法键闺。如果不這樣做的話寿烟,就會違反Object.hashCode的通用約定,從而導(dǎo)致該類無法結(jié)合所有基于散列的集合一起正常運(yùn)作辛燥,這樣的集合包括HashMap筛武、HashSet和Hashtable。

在應(yīng)用程序的執(zhí)行期間挎塌,只要對象的equals方法的比較操作所用到的信息沒有被修改徘六,那么對這同一個對象調(diào)用多次,hashCode方法都必須始終如一地返回同一個整數(shù)榴都。在同一個應(yīng)用程序的多次執(zhí)行過程中待锈,每次執(zhí)行所返回的整數(shù)可以不一致。

如果兩個對象根據(jù)equals()方法比較是相等的缭贡,那么調(diào)用這兩個對象中任意一個對象的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果炉擅。

如果兩個對象根據(jù)equals()方法比較是不相等的辉懒,那么調(diào)用這兩個對象中任意一個對象的hashCode方法阳惹,則不一定要產(chǎn)生相同的整數(shù)結(jié)果谍失。但是程序員應(yīng)該知道,給不相等的對象產(chǎn)生截然不同的整數(shù)結(jié)果莹汤,有可能提高散列表的性能快鱼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纲岭,隨后出現(xiàn)的幾起案子抹竹,更是在濱河造成了極大的恐慌,老刑警劉巖止潮,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窃判,死亡現(xiàn)場離奇詭異,居然都是意外死亡喇闸,警方通過查閱死者的電腦和手機(jī)袄琳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來燃乍,“玉大人唆樊,你說我怎么就攤上這事】绦罚” “怎么了逗旁?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舆瘪。 經(jīng)常有香客問我片效,道長,這世上最難降的妖魔是什么英古? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任淀衣,我火速辦了婚禮,結(jié)果婚禮上哺呜,老公的妹妹穿的比我還像新娘舌缤。我一直安慰自己,他們只是感情好某残,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布国撵。 她就那樣靜靜地躺著,像睡著了一般玻墅。 火紅的嫁衣襯著肌膚如雪介牙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天澳厢,我揣著相機(jī)與錄音环础,去河邊找鬼囚似。 笑死,一個胖子當(dāng)著我的面吹牛线得,可吹牛的內(nèi)容都是我干的饶唤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼贯钩,長吁一口氣:“原來是場噩夢啊……” “哼募狂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起角雷,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤祸穷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勺三,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雷滚,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年吗坚,在試婚紗的時候發(fā)現(xiàn)自己被綠了祈远。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡刻蚯,死狀恐怖绊含,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炊汹,我是刑警寧澤躬充,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站讨便,受9級特大地震影響充甚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霸褒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一伴找、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧废菱,春花似錦技矮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至旁理,卻和暖如春樊零,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孽文。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工驻襟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夺艰,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓沉衣,卻偏偏與公主長得像郁副,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厢蒜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

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