HashMap存自定義對象爲什麼要重寫 hashcode 和 equals 方法?

HashMap的k放過自定義對象麼?
當我們把自定義對象存入HashMap中時,如果不重寫hashcode和equals這兩個方法,會得不到預期的結果。

class Key{
    private Integer id;

    public Integer getId() {
        return id;
    }

    public Key(Integer id) {
        this.id = id;
    }
}

public class WithoutHashCode{
    public static void main(String[] args){
       //定義兩個對象,並聲明他倆的id全是1
        Key k1 = new Key(1);
        Key k2 = new Key(1);
        HashMap<Key,String> map = new HashMap<Key,String>();
        map.put(k1, "Key with id is 1");
        System.out.println(map.get(k2));
    }
}

在這裏把k1對象作爲鍵put進HashMap,再用k2來get出來並打印。如果沒有重寫hashcode和equals方法,最終只能得到一個null。
原因很簡單,由於我們沒有重寫hashcode方法,所以在往HashMap中放入k1時依舊調用的是Object類的hashcode方法,返回的是k1對象的內存地址。如果是用map.get(k1)來查找,就能很快得到value值。
但遺憾的是,我們偏偏是用的k2來get。Object的hashcode方法返回的是k2的內存地址,肯定和k1的不相同,換句話說就是他倆的hash值不同,所以不能用k2的hash值拿到k1的value。

重寫hashCode和equals方法
class Key{
    private Integer id;

    public Integer getId() {
        return id;
    }

    public Key(Integer id) {
        this.id = id;
    }
    @Override
    public boolean equals(Object o) {
        if (o==null || !(o instanceof Key)){
            return false;
        }else {
            return this.getId().equals(((Key)o).getId());
        }
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}

只重寫了hashCode方法後,這裏的hashCode方法return的是id的hashCode值。因爲我們之前將兩個對象的id都設爲1,所以他倆的hash值是一樣的。
接下來我們再去map.get(k2),會不會拿到value呢?結果還是null。目瞪狗呆有木有?爲啥嘞?不是都已經使他倆的hashCode相同了嘛?因爲我們只是重寫了hashCode方法,並沒有重寫equals方法啊。不要忘了,HashMap是用鏈地址法來處理碰撞衝突的。也就是說,某一條鏈表上的所有的元素的hashCode返回的hash值全是一樣的。只重寫hashCode方法只能證明k1和k2的hash值相同,當時並不代表他倆就是相等。沒有重寫equals方法,又是會調用Object類中的equals方法,判斷的依舊是兩個對象的內存地址!
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章