在Java的基類java.lang.Object中有兩個非常重要的方法:
public boolean equals(Object obj) public int hashCode()
對這兩個方法的理解非常重要,特別是當用戶自己定義對象,並將其存入到Map中的時候;
然而,即便是高級開發人員,有時候也搞不清楚如何正確的使用它們;
在這篇文章,我首先會展示一種常見的錯誤示例,然後解釋如何正確的使用這兩個方法;
如下代碼是常見的錯誤使用示例:
package simplejava; import java.util.HashMap; class Apple { private String color; public Apple(String color) { this.color = color; } public boolean equals(Object obj) { if (!(obj instanceof Apple)) return false; if (obj == this) return true; return this.color.equals(((Apple) obj).color); } } public class Q9 { public static void main(String[] args) { Apple a1 = new Apple("green"); Apple a2 = new Apple("red"); // hashMap stores apple type and its quantity HashMap<Apple, Integer> m = new HashMap<Apple, Integer>(); m.put(a1, 10); m.put(a2, 20); System.out.println(m.get(new Apple("green"))); } }
在這個例子中,一個綠色蘋果對象成功存入到hashMap中,但是當我們要取出來的時候,得到的卻是null;然而通過調試程序,我們確實看到了hashmap中的綠蘋果對象;
之所以出現這個錯誤是因為沒有重寫hashCode()方法導致的。
hashCode()和equals()的關系是這樣的:
如果兩個對象相等(equal),它們的hashcode一定相同;
如果兩個對象有相同的hashcode,它們不一定相等(equal);
之所以這樣設計是為了在Map中更快的查找到對象(相對於線性搜索);
一般Map都設計成數組+鏈表的結構,使用hashcode去查找對象需要兩個步驟,首先使用hashcode定位數組下標索引,然後遍歷該數組元素對應的鏈表,找到equals的元素;
Object默認的hashcode實現對於不同的對象會返回不同的值,因此,在上面那個例子中,不同的對象(即使同一個類型)有著不同的hashcode;
值的散列就像在車庫儲存貨物,不同的貨物能被存放到不同的車庫。比較有效查找貨物辦法是將不同的貨物存到不同的車庫中,而不是同一個車庫;
所以將hash值盡可能的分散是一個比較好的策略;
關於這個例子,解決辦法是添加hashcode方法,這裡我將使用顏色的長度作為示范,如下代碼:
public int hashCode(){ return this.color.length(); }
譯文鏈接:http://www.programcreek.com/2011/07/java-equals-and-hashcode-contract/