Java对象默认的equals方法都是比较两个对象的地址的。
如果要重写equals方法,要满足一下四点:
Reflexive(自反性):即 x.equals(x)必须是true
Symmetric(对称性):即如果 x.equals(y)返回true,那么y.equals(x)也必须返回true
Transitive(传递性):即如果 x.equals(y)返回true, y.equals(z)也返回true,那么x.equals(z)也必须返回true
Consistent(一致性):即多次调用 x.equals(y)返回的结果必须保持一致。
非空特性:即对于非空对象x,x.equals(null)总是返回false
hashCode这个方法是为了在使用HashMap HashSet LinkedHashMap LinkedHashSet等数据结构的时候,为了更快速的找到key而产生的,其中通过求key的hashcode迅速找到对应的bucket位置,然后再通过equals方法来找到bucket所指向的链表里面的对应的value。这也就是为什么在重写equals方法是也要重写hashCode方法,这是为了让equals返回true的时候两个对象的hashCode必须相等,但是反之则不一定了。
那么如何写出有效的hashCode函数呢?其实最重要的是要提取出对象的重要属性。Java大神Joshua Bloch曾经在他的大作《Effective Java》这样定义一个有效的hashCode函数的产生过程:
1、去一个非零常量,比如17,将它赋给变量result
2、为每一个在equals方法里面用到过的属性计算它们的hash值c:
- 如果属性变量是bool值:
c = (f ? 0 : 1)
;
- byte, char, short 或者 int:
c = (int)f
; - long:
c = (int)(f ^ (f >>> 32))
; - float: c =
Float.floatToIntBits(f)
; - double:c =
Double.doubleToLongBits(f),然后执行之前处理long的步骤
; - object: c=(f == null?0:f.
hashCode())
; - array: 将数组里面的值按照上面的处理方法处理
3、将所有的值以下形式计算
result = 37 * result + c
4、返回结果