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方法,判斷的依舊是兩個對象的內存地址!