参考博客:【1】hash冲突解决方法
【2】hashCode()函数与equals的作用与区别
Hash冲突
处理方法:
(1)开放定址法(线性探测再散列,二次探测再散列,随机探测再散列)
(2)链地址法:将产生冲突的对象链接再同一链表中。(hashmap处理冲突的方法)
(3)再哈希法:重复计算hash,直到不发生冲突为止。
(3)建立公共溢出区:将所有的冲突数据存在这个地方,不存在表中。
简述
把任意长度的输入,通过Hash算法变成固定长度的输出,几位Hash值。由于哈希值空间远小于输入空间,故可能发生hash碰撞,即两个不同的输入,产生了同一个输出。
使用
对于分布式系统,存在负载均衡和数据分布问题,为了让请求(或数据)分布更加均匀,很多时候使用Hash算法。
-
Hash取模(hash(request)%n)
假设有3个服务器,做负载均衡,可对请求的ip地址使用Hash函数,然后计算出的值对3取模,余数为几,就把请求分到相应的服务器。
缺点: 一旦新增或删除服务器,大部分请求会重新映射到新的节点,这样会存在问题,对于Web负载均衡场景,session会保存在每个节点中,大量的数据需要迁移。 -
一致性Hash
解决因为横向绳索导致的大规模数据变动。
一致性Hash的模是2(32),从0到2(32) -1,首位相连构成一个环。先对服务器节点的IP进行Hash,然后对2(32)取余,得到服务器节点在Hash环中的位置,如果请求进来了,同样进行Hash然后对2(32)取余。如果落在Hash环上,然后按顺时针找到第一个节点,这个节点负责处理这个请求。一致性Hash算法在节点数量较少的时候,会出现分布不均匀的问题
解决这个问题的方案就是在Hash环上增加虚拟节点
哈希表简介
- 非哈希表特点:关键字在表中的位置和关键字之间不存在一个确定的关系,查找的过程为给定值一次与各个关键字进行比较,查找的效率取决于和给定值进行比较的次数。
- 哈希函数:需要在关键字key与它在表中的位置之间建立一个函数关系,称这个函数f(key)为哈希函数,记录关键字key在表中的存储位置。
- hash:“散列”,把任意长度的输入,通过散列算法,变成固定函数输出,输出即为散列值。散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值推导唯一的确定输入值。
- hash冲突:根据关键字key经过一个函数h(key)得到的结果作为地址,去存放当前的key-value键值对(hashmap存值方式),却发现地址上已经存有内容。
哈希函数处理冲突的方法
1. 开放定址法
![](https://i-blog.csdnimg.cn/blog_migrate/df5dd5be2e4280c20bad8942530836a8.png)
- 线性探测再散列:di = 1 , 2 , 3 , … , m-1
- 平方探测再散列 di = 1 , -1 , 2, -2 , 3 , -3 , … , k , -k(取相应数的平方)
- 随机探测再散列 di 是一组伪随机数列
![](https://i-blog.csdnimg.cn/blog_migrate/dbb6224e29ccf77e3b8c75fc94fbb70b.png)
2. 链地址法
![](https://i-blog.csdnimg.cn/blog_migrate/3a952971a35b0572184633dfd2ae768b.png)
3. 再哈希
![](https://i-blog.csdnimg.cn/blog_migrate/3a952971a35b0572184633dfd2ae768b.png)
4. 建立公共溢出区
建立一个公共溢出区,将冲突的都放在另一个地方,不放在表中。
hashCode与equals的作用与区别
-
非哈希表特点:
关键字与关键字在表中存储地址无确定关系,当需要查找表中是否存在某个元素时,需要与表中所有元素逐一进行equals比较。 -
哈希表特点:
关键字key与关键字在表中存储位置存在一种压缩映射关系,称这种关系f(key)为哈希函数,记录关键字key在表中的存储位置。从而提高查找效率。 -
equals(Object obj)和hashCode()函数定义:Java中任何对象都具备这两个方法,equals(Object obj)方法用来判断两个对象是否“相同”,hashCode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。
-
归纳总结:
1.若重写了equals(Object obj)方法,则有必要重写hashCode()方法。
2.若两个对象equals(Object obj)返回true,则hashCode()有必要也返回相同的int数。
3.若两个对象equals(Object obj)返回false,则hashCode()不一定返回不同的int数。
4.若两个对象hashCode()返回相同int数,则equals(Object obj)不一定返回true。
5.若两个对象hashCode()返回不同int数,则equals(Object obj)一定返回false。
6.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。
“内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。”
- 对象存入散列集合中:
对象存入HashTable,HashSet,HashMap等散列存储结构中,如果重写equals最好也重写hashCodes,否则会导致存储数据的不唯一性(存储了两个equals相等的数据)。
对象放入散列集合的流程图:
散列集合存储一个对象时,先进行hashCode值比较,然后进行equals比较。
- 对象存入非散列表中:
如果确定不会存储在这些散列结构中,则可以不重写hashCode。
总结:
1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。
2.equals和hashCode需要同时覆盖。
7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。