因为hashMap,hashSet等数据结构是依赖hashCode判断两个对象是否是一致的,如重写了equals,不重写hashCode,会有以下问题。
运行这段代码发现结果返回的是null。
再来看一下HashMap中的get源码:
get的时候会先比较hashCode然后再去比较equals, 返回结果为null其实都是hashCode惹的祸。
所以重写equals必须重写hashCode。不然在hashMap,hashSet等结构中不能使用。
那为什么hashSet,hasMap等数据结构要使用hashCode呢? 为什么他们不使用equals呢? 答案是因为效率问题。
我们都知道java中的List集合是有序的,因此是可以重复的,而set集合是无序的,因此是不能重复的,那么怎么能保证不能被放入重复的元素呢,但靠equals方法一样比较的话,如果原来集合中以后又10000个元素了,那么放入10001个元素,难道要将前面的所有元素都进行比较,看看是否有重复,欧码噶的,这个效率可想而知,因此hashcode就应遇而生了,java就采用了hash表,利用哈希算法(也叫散列算法),就是将对象数据根据该对象的特征使用特定的算法将其定义到一个地址上,那么在后面定义进来的数据只要看对应的hashcode地址上是否有值,那么就用equals比较,如果没有则直接插入,只要就大大减少了equals的使用次数,执行效率就大大提高了。
注意:
并且如果我们将某个自定义对象存到HashMap或者HashSet及其类似实现类中的时候,如果该对象的属性参与了hashCode的计算,那么就不能修改该对象参数hashCode计算的属性了。有可能会移除不了元素,导致内存泄漏。
hash表数据结构示意:(链表的数组)
hashCode() 与 equals() 的相关规定:
1. 如果两个对象相等,则 hashcode ⼀定也是相同的
2. 两个对象相等,对两个 equals() ⽅法返回 true
3. 两个对象有相同的 hashcode 值,它们也不⼀定是相等的
4. 综上, equals() ⽅法被覆盖过,则 hashCode() ⽅法也必须被覆盖
5. hashCode() 的默认⾏为是对堆上的对象产⽣独特值。如果没有重写 hashCode() ,则该 class 的两个对象⽆论如何都不会相等(即使这两个对象指向相同的数据)。