java hashcode

在Java中有个java.lang.Object的超类,定义了2个非常重要的方法:

1
2
public boolean equals(Object obj)
public int hashCode()

它们是非常被非常重要的,所以有必要理解它们,特别是当用户添加自定义的对象被到Map上的时候。即使是这样,有的高级工程师有时也弄不清应应该如何正确使用。在这篇文章中,我将首先用一个常见的错误例子,来说明equals()和hashCode是如何工作的。

1.一个常见错误

下面的例子是一个常见的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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对象被成功的保存在hashMap中,但是当需要获得这个对象的时候,却显示没有存在。这个程序输出了null。但是我们确定添加了一个green的apple的,我们用debug模式发现这2个对象时不同的。如下:

java hashcode

2. 问题的来源是hashCode()方法

这个问题的原因是没有复写“hashCode()”方法。对于quals() 和 hasCode() 来说:

  • 如果两个对象相等,他们必须有相同的hash code。
  • 如果两个对象有相同的hashcode,他们可能相等也有可能不等。

这样的设计方式,是为了在Map中获得对象比线性搜索更加的快速。使用哈希值去找一个对象只需要2步就可以了。Map的内部实现是先用哈希值获得数组,然后线性的使用equals()判断这个对象是不是找到了。

在Object类中的默认实现是,为不同对象返回不同的哈希值。于是在上面的例子中,两个对象(即使是相同类型)也是不同的哈希值。

Hash Code 就像车库存放车一样,不同的车能放在不同的车库。这样的方式很有效,对于你想知道不同的车放在哪,只需要对应车库的号码就行。使用使用哈希值来判断相不相等是很好的做法。

解决方式当然是复写hashCode()方法了,下面是根据颜色的字符串长度来产生哈希值:

1
2
3
public int hashCode(){
return this.color.length();
}

参考文档