原文 Java equals() and hashCode() Contract
在java父类Object中定义了2个重要的方法
public boolean equals(Object obj)
public int hashCode()
理解这两个方法非常重要,尤其是用户自定义的类型用在Map中作key,然而,即使高级开发者有时也无法正确使用它们。下面通过一个常见的错误作例子来说明它们是如何工作的。
1,常见错误
import java.util.HashMap;
public 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 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")));
}
}
在该例中,一个green apple object已添加到HashMap中,当要从中取出该对象对应的value时,该对象却没有被找到。上面的程序返回的是null。
2,由hashCode()导致的问题
问题是由于没有重写hashCode()方法导致的,equaels()和hashCode()的关系是这样的:
1),如果2个对象的相同的,那它们的hashCode一定相同
2),如果2个对象的hashCode相同,那它们可能相同也可能不相同
使用Map的本意是为了比线性查找更快的找到一个对象。用hashcode定位一个对象分2步。在Map内部存储对象用了一个二维数组,第一维数组的index即是key的hashcode值,用该index定位到第二维数组,在第二维数组中用equaels()方法线性查找是否存在某对象。
Object中hashCode()的默认实现是不同对象返回不同的integer值,上面例子中即使是同样类型,不同对象的hashcode也不同。
hashcode就像是用于存储一系列的仓库,不同的物品存放在不同的仓库中,如果可以将同一仓库中的不同物品分配一个唯一的位置,那就更有效率了。所以,正确分发hashcode值更重要。
上例的解决方案即是重写hashCode(),这里用String的长度作演示。
public int hashCode(){
return this.color.length();
}
---------------2015.5.10-----------------
另一篇文章Java hashCode() 和 equals()的若干问题解答对equals和hashCode讲解得更清楚。