equals() 与 hashCode
以下来自网络:
object的equals()和hashCode()比较的是两个对象的地址的整数值,这是object的默认实现。在实际应用中,我们经常需要覆盖这两个方法,规则和原因如下:
hashCode()返回一个对象的hash 代码,在hashtable数据结构实现的集合中,它决定了这个对象被放到哪个bucket(篮子)中。一个bucket中可能存放了多个对象。而equals方法则是进一步到bucket寻找具体对象的依据。
为了hashtable数据结构能正常工作,hashCode方法的通用协议是:equals方法定为相等的两个对象的hashCode()返回的整数一定相同。只有这样才能在hashtable数据结构中找到这个对象。而equals方法定为不相等的两个对象的hashCode()返回的整数可以不相同,如果相同则为哈西冲突。所以尽量保证equals方法定为不相等的对象的hashCode()返回的整数不相同。
类Object实现的hashCode使用对象的内部地址转化为整数返回,使得o1.equals(o2)当且仅当o1.hashCode()== o2.hashCode
[b]总结:[/b]
网上关于hashCode与equals的文章许多,但没几个说的很透彻的。下面是我的一点体会。
如果采用数组来存取数据的话,要查找某一个key,时间复杂度是O(n),如果已经排了序,可以采用二分查找,时间复杂度为O(log2n).如果能有这样一种方法,将key的值与存储地址一一对应,那么效率就会有很大的提高。我们就采用一个哈西函数Hey(key),该函数的返回值就是存储的地址,比如y=value%n+1(这是一个比较常用的除留余数法).n指的是将要存储的元素的个数。为什么函数要和元素的个数有关系呢?因为存储必然要开辟空间,而空间应该尽量连续,元素和元素之间尽量没有空间浪费,当然Hey(key)有许多不同的算法来计算地址来达到这一个目的。朋友一定会发现上面的除留余数法很可能出现这样的问题,相同的value一定产生相同的y,但不同的value很可能产生相同的y。这就是hash冲突。当遇到这样的情况,我们可以利用这样的一个函数Mey(y):y= (Hey(value)+1)%m,m为地址空间的小篮子的数量,m一定大于n。假如我们想在18个空间放13个元素,m=18,n=13.还有一种处理冲突的办法叫做链表法,也就是说将会有18个链表,每个存储地址指向这个链表的首地址,相当于每个地址都是篮子,里面装的是hashcode相等但value不同的元素。关于hash存储就说到这里,这里建议去参考教材。
另外假如value的值特别大,y的值有可能会非常大,所以y不能直接作为存储地址,而是y和存储地址还有一个一一对应的关系。我们可以简单的看成value对应地址。
说道这里,想必朋友们已经知道hashcode和equals的关系了。HashMap ,HashSet作为集合的容器,采用的是hash存储。Hashcode就是hash函数,hashSet与hashMap的功能大家都知道,就是key唯一。假如我们加入的元素认为相等而他的hashcode不等,则会存储两个相等的元素,也就不能正常工作。道理朋友们想去吧。这也就要求我们覆盖hashcode的时候应该和equals保持一致,还要注意程序的健壮性,比如null的判断。同时还应该尽量让那个不等的元素的hashcode也要不等,考虑到性能。
说起性能不得不提负载因子,其实就是n/m(13/18).这个值越大说明实现开辟好的存储空间越满,值越小那么冲突与查找的性能也就越好,试想,在一个100个空间里查找3个元素,是不是很浪费?或者我要遍历这个空间,是不也会很慢?所以我们要做一个空间与时间的权衡。hashMap与hashset的默认负载因子是0.75也就是空间还有三分之一的空间,hashMap与hashset创建的时候可以指定空间的容量。根据实际情况我们可以设置初始值。
以下来自网络:
object的equals()和hashCode()比较的是两个对象的地址的整数值,这是object的默认实现。在实际应用中,我们经常需要覆盖这两个方法,规则和原因如下:
hashCode()返回一个对象的hash 代码,在hashtable数据结构实现的集合中,它决定了这个对象被放到哪个bucket(篮子)中。一个bucket中可能存放了多个对象。而equals方法则是进一步到bucket寻找具体对象的依据。
为了hashtable数据结构能正常工作,hashCode方法的通用协议是:equals方法定为相等的两个对象的hashCode()返回的整数一定相同。只有这样才能在hashtable数据结构中找到这个对象。而equals方法定为不相等的两个对象的hashCode()返回的整数可以不相同,如果相同则为哈西冲突。所以尽量保证equals方法定为不相等的对象的hashCode()返回的整数不相同。
类Object实现的hashCode使用对象的内部地址转化为整数返回,使得o1.equals(o2)当且仅当o1.hashCode()== o2.hashCode
[b]总结:[/b]
网上关于hashCode与equals的文章许多,但没几个说的很透彻的。下面是我的一点体会。
如果采用数组来存取数据的话,要查找某一个key,时间复杂度是O(n),如果已经排了序,可以采用二分查找,时间复杂度为O(log2n).如果能有这样一种方法,将key的值与存储地址一一对应,那么效率就会有很大的提高。我们就采用一个哈西函数Hey(key),该函数的返回值就是存储的地址,比如y=value%n+1(这是一个比较常用的除留余数法).n指的是将要存储的元素的个数。为什么函数要和元素的个数有关系呢?因为存储必然要开辟空间,而空间应该尽量连续,元素和元素之间尽量没有空间浪费,当然Hey(key)有许多不同的算法来计算地址来达到这一个目的。朋友一定会发现上面的除留余数法很可能出现这样的问题,相同的value一定产生相同的y,但不同的value很可能产生相同的y。这就是hash冲突。当遇到这样的情况,我们可以利用这样的一个函数Mey(y):y= (Hey(value)+1)%m,m为地址空间的小篮子的数量,m一定大于n。假如我们想在18个空间放13个元素,m=18,n=13.还有一种处理冲突的办法叫做链表法,也就是说将会有18个链表,每个存储地址指向这个链表的首地址,相当于每个地址都是篮子,里面装的是hashcode相等但value不同的元素。关于hash存储就说到这里,这里建议去参考教材。
另外假如value的值特别大,y的值有可能会非常大,所以y不能直接作为存储地址,而是y和存储地址还有一个一一对应的关系。我们可以简单的看成value对应地址。
说道这里,想必朋友们已经知道hashcode和equals的关系了。HashMap ,HashSet作为集合的容器,采用的是hash存储。Hashcode就是hash函数,hashSet与hashMap的功能大家都知道,就是key唯一。假如我们加入的元素认为相等而他的hashcode不等,则会存储两个相等的元素,也就不能正常工作。道理朋友们想去吧。这也就要求我们覆盖hashcode的时候应该和equals保持一致,还要注意程序的健壮性,比如null的判断。同时还应该尽量让那个不等的元素的hashcode也要不等,考虑到性能。
说起性能不得不提负载因子,其实就是n/m(13/18).这个值越大说明实现开辟好的存储空间越满,值越小那么冲突与查找的性能也就越好,试想,在一个100个空间里查找3个元素,是不是很浪费?或者我要遍历这个空间,是不也会很慢?所以我们要做一个空间与时间的权衡。hashMap与hashset的默认负载因子是0.75也就是空间还有三分之一的空间,hashMap与hashset创建的时候可以指定空间的容量。根据实际情况我们可以设置初始值。