HashCode和equals()

Java中的equals方法和hashCode方法是Object中的塌忽,所以每個對象都是有繼承這兩個方法的,有時候我們需要實現(xiàn)特定需求桐经,可能要重寫這兩個方法拓哟。

比如:HashMap、HashTable河泳、HashSet沃呢,所以涉及到使用hash值進行優(yōu)化存儲的地方,都會用到hashCode拆挥。
1.首先調(diào)用對象的hashCode()方法獲得該對象的哈希碼表薄霜。
2.然后根據(jù)哈希嗎找到相應(yīng)的存儲區(qū)域。
3.最后取得該存儲區(qū)域內(nèi)的每個元素與該對象進行equals方法比較纸兔。
這樣就不用遍歷集合中的所有元素就可以得到結(jié)論惰瓜,可見HashSet集合具有很好的對象檢索性能。

hash與equals的關(guān)系:
hashCode就好比字典里每個字的索引汉矿,equals()好比比較的是字典里同一個字下的不同詞語崎坊。

  • 不管執(zhí)行多少次獲取hash值的操作,只要對象不變洲拇,那么hash值是固定的
  • 若兩個對象equals方法返回為true奈揍,則其hash值也應(yīng)該是一樣的。
  • 若兩個對象equals方法返回為false赋续,則其hash值可能相同男翰。

下面來看一下一個具體的例子:
RectObject對象:

package com.weijia.demo;  
  
public class RectObject {  
    public int x;  
    public int y;  
    public RectObject(int x,int y){  
        this.x = x;  
        this.y = y;  
    }  
    @Override  
    public int hashCode(){  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        return result;  
    }  
    @Override  
    public boolean equals(Object obj){  
        if(this == obj)  
            return true;  
        if(obj == null)  
            return false;  
        if(getClass() != obj.getClass())  
            return false;  
        final RectObject other = (RectObject)obj;  
        if(x != other.x){  
            return false;  
        }  
        if(y != other.y){  
            return false;  
        }  
        return true;  
    }  
}  

我們重寫了父類Object中的hashCode和equals方法,看到hashCode和equals方法中纽乱,如果兩個RectObject對象的x,y值相等的話他們的hashCode值是相等的蛾绎,同時equals返回的是true;
下面是測試代碼:

package com.weijia.demo;  
import java.util.HashSet;  
public class Demo {  
    public static void main(String[] args){  
        HashSet<RectObject> set = new HashSet<RectObject>();  
        RectObject r1 = new RectObject(3,3);  
        RectObject r2 = new RectObject(5,5);  
        RectObject r3 = new RectObject(3,3);  
        set.add(r1);  
        set.add(r2);  
        set.add(r3);  
        set.add(r1);  
        System.out.println("size:"+set.size());  
    }  
}  
  • 我們向HashSet中存入到了四個對象,打印set集合的大小迫淹。
    運行結(jié)果:size:2
    因為重寫了RectObject類的hashCode方法秘通,只要RectObject對象的x,y屬性值相等那么他的hashCode值也是相等的,先比較hashCode的值敛熬,r1和r2對象的x,y屬性值不等肺稀,所以他們的hashCode不相同的,所以r2對象可以放進去应民,但是r3對象的x,y屬性值和r1對象的屬性值相同的话原,所以hashCode是相等的夕吻,這時候在比較r1和r3的equals方法,因為他么兩的x,y值是相等的繁仁,所以r1,r3對象是相等的涉馅,所以r3不能放進去了,同樣最后再添加一個r1也是沒有沒有添加進去的黄虱,所以set集合中只有一個r1和r2這兩個對象

  • 下面我們把RectObject對象中的hashCode方法注釋稚矿,即不重寫hashCode方法,再運行一下代碼:
    運行結(jié)果:size:3
    這個結(jié)果也是很簡單的捻浦,首先判斷r1對象和r2對象的hashCode晤揣,因為Object中的hashCode方法返回的是對象本地內(nèi)存地址的換算結(jié)果,不同的實例對象的hashCode是不相同的朱灿,同樣因為r3和r1的hashCode也是不相等的昧识,但是r1==r1的,所以最后set集合中只有r1,r2,r3這三個對象盗扒,所以大小是3

  • 下面我們把RectObject對象中的equals方法中的內(nèi)容注釋跪楞,直接返回false,放開hashCode方法的注釋侣灶,運行一下代碼:
    運行結(jié)果:size:3
    這個結(jié)果就有點意外了甸祭,我們來分析一下:
    首先r1和r2的對象比較hashCode,不相等炫隶,所以r2放進set中淋叶,再來看一下r3,比較r1和r3的hashCode方法,是相等的伪阶,然后比較他們兩的equals方法煞檩,因為equals方法始終返回false,所以r1和r3也是不相等的,r3和r2就不用說了栅贴,他們兩的hashCode是不相等的斟湃,所以r3放進set中,再看r4,比較r1和r4發(fā)現(xiàn)hashCode是相等的檐薯,在比較equals方法凝赛,因為equals返回false,所以r1和r4不相等,同一r2和r4也是不相等的坛缕,r3和r4也是不相等的墓猎,所以r4可以放到set集合中,那么結(jié)果應(yīng)該是size:4,但為什麼是3呢赚楚?
    其實HashSet首先是判斷hashCode是否相等毙沾,不相等的話,直接跳過宠页,相等的話左胞,然后再來比較這兩個對象是否相等或者這兩個對象的equals方法寇仓,因為是進行的或操作,所以只要有一個成立即可烤宙,那這里我們就可以解釋了遍烦,其實上面的那個集合的大小是3,因為最后的一個r1沒有放進去,以為r1==r1返回true的躺枕,所以沒有放進去了服猪。所以集合的大小是3。

最后我們在來看一下hashCode造成的內(nèi)存泄露的問題:看一下代碼:

package com.weijia.demo;  
import java.util.HashSet;  
public class Demo {  
    public static void main(String[] args){  
        HashSet<RectObject> set = new HashSet<RectObject>();  
        RectObject r1 = new RectObject(3,3);  
        RectObject r2 = new RectObject(5,5);  
        RectObject r3 = new RectObject(3,3);  
        set.add(r1);  
        set.add(r2);  
        set.add(r3);  
        r3.y = 7;  
        System.out.println("刪除前的大小size:"+set.size());  
        set.remove(r3);  
        System.out.println("刪除后的大小size:"+set.size());  
    }  
}  

運行結(jié)果:
刪除前的大小size:3
刪除后的大小size:3
調(diào)用了remove刪除r3對象拐云,以為刪除了r3,但事實上并沒有刪除蔓姚,這樣多次這樣操作之后,內(nèi)存就爆了慨丐。因為在調(diào)用remove方法的時候,會先使用對象的hashCode值去找到這個對象泄私,然后進行刪除房揭,但我們在修改了r3對象的y屬性的值,又因為RectObject對象的hashCode方法中有y值參與運算,所以r3對象的hashCode就發(fā)生改變了晌端,所以remove方法中并沒有找到r3了捅暴,所以刪除失敗。即r3的hashCode變了咧纠,但是他存儲的位置沒有更新蓬痒,仍然在原來的位置上,所以當(dāng)我們用他的新的hashCode去找肯定是找不到了漆羔。


要點:
Object中的hashCode方法返回的是對象本地內(nèi)存地址的換算結(jié)果梧奢。
HashSet判斷要放入的元素是否相等:
1.hashcode是否相等,不相等放入演痒。
2.如果hashcode相等亲轨,判斷equals方法和==方法,如果都不相等放入鸟顺。equals和==方法只要有一個相等惦蚊,HashSet認為是相同的元素。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末讯嫂,一起剝皮案震驚了整個濱河市蹦锋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌欧芽,老刑警劉巖莉掂,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異渐裸,居然都是意外死亡巫湘,警方通過查閱死者的電腦和手機装悲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尚氛,“玉大人诀诊,你說我怎么就攤上這事≡乃唬” “怎么了属瓣?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讯柔。 經(jīng)常有香客問我抡蛙,道長,這世上最難降的妖魔是什么魂迄? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任粗截,我火速辦了婚禮,結(jié)果婚禮上捣炬,老公的妹妹穿的比我還像新娘熊昌。我一直安慰自己,他們只是感情好湿酸,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布婿屹。 她就那樣靜靜地躺著,像睡著了一般推溃。 火紅的嫁衣襯著肌膚如雪昂利。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天铁坎,我揣著相機與錄音蜂奸,去河邊找鬼。 笑死硬萍,一個胖子當(dāng)著我的面吹牛窝撵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播襟铭,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼碌奉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了寒砖?” 一聲冷哼從身側(cè)響起赐劣,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎哩都,沒想到半個月后魁兼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡漠嵌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年咐汞,在試婚紗的時候發(fā)現(xiàn)自己被綠了盖呼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡化撕,死狀恐怖几晤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情植阴,我是刑警寧澤蟹瘾,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站掠手,受9級特大地震影響憾朴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喷鸽,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一众雷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧做祝,春花似錦报腔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纤房。三九已至纵隔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炮姨,已是汗流浹背捌刮。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舒岸,地道東北人绅作。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蛾派,于是被迫代替她去往敵國和親俄认。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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