hashCode() 方法有什么作用呢?

一.引言

首先 hashCode() 方法被设计在 Object 类中,说明是希望所有的对象都能实现该方法,该方法是会返回一个对应于当前对象的一个整数,之所以所有对象都实现该方法是为了将来对象在查找时变得快捷。

  • Java中的集合类 hashMap、hashSet 底层的实现都是哈希表,之所以采用哈希表,是因为他能克服链表和二叉树等数据结构在查询上的低效率问题,哈希表的存储就是根据对象的哈希值,以此确定他的存储位置。
  • 但是,仅仅通过 hashcode() 并不能将所有对象区分开来,有可能会出现对象不同,hashcode 值却相同的情况。
  • 为了充分将对象区分开,Object 类中还有一个方法 equals(), 该方法便是在当对象的 hashcode 值相同的情况下,判断两个对象是否相同。
  • 通过上面分析可知,hashCode() 方法和 equals() 方法往往都是配合使用的,当我们重写了 equals() 方法时,必须要重写hashCode方法,这是java中的一条规定。
  • 原因很简单,假如此处有 A,B 两个对象,他们内容相同,当我们在重写equals() 之前,equals 值是 false,因为重写之前 equals 相当于 ==,对于引用类型来说,就是比较地址值是否相同,但是这是两个对象,地址值肯定不同。而且他们的 hashCode 值也不相同,因为为重写前的 hashCode 值与 对象存储位置 有关,而这是两个对象,所以存储位置肯定不同。因此重写这两个方法前,它们的值都不等。
  • 但是,重写之后 equals() 返回了 true,因为这两个对象的内容是相同的,而此时他们的 hashCode 值仍然不相同,因为没有重写这个方法。这明显就不符合逻辑,因为 equals() 相同的对象 hashCode 值肯定相同,因此重写 equals 的同时,有必要重写 hashCode (根据自己的需求来写) 方法,总之两者要同时进行。
  • 通过上面的分析,我们发现 hashCode() 方法无非就是用来确定对象的存储位置的,以及对象之间进行比较,这些都是为哈希表的查找效率进行服务的。

二.具体分析

总的来说,Java 中的集合(Collection)有两类,一类是List,再有一类是Set。
前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复

问题:要想保证元素不重复,应该怎么来判断呢?

  • 这就要用到 Object.equals()方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,添加到集合中的元素比较的次数就非常多了。 也就是说,如果集合中现在已经有1000个元素了,那么第 1001 个元素加入集合时,它就要调用1000次 equals()方法。这显然会大大降低查询效率。

  • 于是,Java采用了哈希表的原理,来解决查找效率低下的问题。

哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。可以这样理解,hashCode() 方法实际上返回的就是对象存储的物理地址。 这样一来,当集合要添加新的元素时,先调用这个元素的 hashCode() 方法,就一下子能定位到它应该放置的物理位置上。 如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有了元素, 就调用它的 equals() 方法与该元素进行比较,相同的话就不存了,不相同的话就散列在其它的地址上。但是这里存在一个冲突解决的问题。一般采用的都是链地址法。

所以,Java 对于 eqauls() 方法和 hashCode() 方法是这样规定的:

1、如果两个对象相同,那么它们的 hashCode 值一定要相同;
2、如果两个对象的 hashCode() 值相同,这两个对象并不一定相同 ;


总结:

1、hashCode() 方法的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode() 方法是用来在散列存储结构中确定对象的存储地址的

2、如果两个对象相同,就是适用于 equals(Java.lang.Object) 方法,那么这两个对象的 hashCode 一定要相同;

3、如果对象的 equals() 方法被重写,那么对象的 hashCode() 也尽量重写;

4、两个对象的 hashCode 值相同,并不一定表示两个对象就相同,也就是不一定适用于 equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如 Hashtable,他们“存放在同一个篮子里”。

再归纳一下就是 hashCode() 是用于查找使用的,而 equals() 是用于比较两个对象的是否相等的。


例如内存中有这样的位置 :

0 1 2 3 4 5 6 7

而我有个类,这个类有个字段叫 ID , 我要把这个类存放在以上 8 个位置之一,如果不用 hashcode 而任意存放,那么当查找时就需要到这八个位置里挨个去找,判断是否存在相同的元素。但如果用 hashcode 那就会使效率提高很多。

但是如果两个类有相同的 hashcode 怎么办?
------例如 9除以 8和 17除以 8的余数都是1,那么这是不是合法的,回答是:可以这样。那么如何判断呢?在这个时候就需要调用 equals() 了

也就是说,我们先通过 hashcode 来判断两个类是否存放某个桶里,但这个桶里可能有很多类,那么我们就需要再通过 equals 来在这个桶里找到我们要的类。

那么,重写了equals(),为什么还要重写hashCode()呢?

想想,你要在一个桶里找东西,你必须先要找到这个桶啊,你不通过重写hashcode()来找到桶,光重写equals()有什么用啊

发布了62 篇原创文章 · 获赞 6 · 访问量 4447

猜你喜欢

转载自blog.csdn.net/HU1656/article/details/104706703