equals,hashCode,==區(qū)別

equals,hashCode,==經(jīng)常會(huì)用到,如果不知道它的規(guī)則,豈不是容易出現(xiàn)隱藏的bug么?

基礎(chǔ)概念

==

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

如果作用于基本數(shù)據(jù)類型,則直接比較其存儲(chǔ)的“值”是否相等; 如果作用于引用類型的變量,則比較的是所指向的對(duì)象的地址

equals

Object 的實(shí)例方法,比較兩個(gè)對(duì)象的content是否相同。

默認(rèn)Object類的equals方法是比較兩個(gè)對(duì)象的地址,跟==的結(jié)果一樣。

Object的equals方法如下:

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

但在一些類庫當(dāng)中這個(gè)方法被覆蓋掉了,如String, Integer, Date在這些類當(dāng)中equals有其自身的實(shí)現(xiàn),而不再是比較類在堆內(nèi)存中的存放地址了。

hashCode

Object 的 native方法 , 獲取對(duì)象的哈希值,用于確定該對(duì)象在哈希表中的索引位置。

它實(shí)際上是一個(gè)int型整數(shù),所以如果沒有重寫hashCode方法,任何對(duì)象的hashCode方法是不相等的。

無論何時(shí),對(duì)同一個(gè)對(duì)象調(diào)用hashCode都應(yīng)該產(chǎn)生同一個(gè)值。

如果重寫了equals方法就必須要重寫hashCode方法,以便用戶將對(duì)象插入到散列表中。


使用注意

equals和hashCode

  1. 如果兩個(gè)對(duì)象equals,Java運(yùn)行時(shí)環(huán)境會(huì)認(rèn)為他們的hashcode一定相等。
  2. 如果兩個(gè)對(duì)象不equals,他們的hashcode有可能相等。
  3. 如果兩個(gè)對(duì)象hashcode相等,他們不一定equals。
  4. 如果兩個(gè)對(duì)象hashcode不相等,他們一定不equals。

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

將對(duì)象放入到集合中時(shí),首先判斷要放入對(duì)象的hashcode值與集合中的任意一個(gè)元素的hashcode值是否相等,如果不相等直接將該對(duì)象放入集合中。

如果hashcode值相等,然后再通過equals方法判斷要放入對(duì)象與集合中的任意一個(gè)對(duì)象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。

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

覆蓋equals方法的時(shí),必須遵守它的通用約定。

  • 自反性。對(duì)于任何非null的引用值x,x.equals(x)必須返回true。
  • 對(duì)稱性。對(duì)于任何非null的引用值x和y,當(dāng)且僅當(dāng)y.equals(x)返回true時(shí),x.equals(y)必須返回true
  • 傳遞性。對(duì)于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必須返回true。
  • 一致性。對(duì)于任何非null的引用值x和y,只要equals的比較操作在對(duì)象中所用的信息沒有被修改,多次調(diào)用該x.equals(y)就會(huì)一直地返回true,或者一致地返回false。

對(duì)于任何非null的引用值x,x.equals(null)必須返回false。

實(shí)現(xiàn)高質(zhì)量equals方法的訣竅:

  1. 使用==符號(hào)檢查“參數(shù)是否為這個(gè)對(duì)象的引用”。如果是,則返回true。這只不過是一種性能優(yōu)化,如果比較操作有可能很昂貴,就值得這么做。
  2. 使用instanceof操作符檢查“參數(shù)是否為正確的類型”。如果不是,則返回false。一般來說,所謂“正確的類型”是指equals方法所在的那個(gè)類。
  3. 把參數(shù)轉(zhuǎn)換成正確的類型。因?yàn)檗D(zhuǎn)換之前進(jìn)行過instanceof測(cè)試,所以確保會(huì)成功.
  4. 對(duì)于該類中的每個(gè)“關(guān)鍵”域,檢查參數(shù)中的域是否與該對(duì)象中對(duì)應(yīng)的域相匹配。如果這些測(cè)試全部成功,則返回true;否則返回false。
  5. 當(dāng)編寫完成了equals方法之后,檢查“對(duì)稱性”、“傳遞性”、“一致性”。

覆蓋equals時(shí)總要覆蓋hashCode

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

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容