哈希算法之 hashCode 为什么选择数字31作为优质乘子?
在hashCode()中,为什么一定要使用31来做乘法运算???
public native int hashCode();
作用:
根据对象在堆内存中的首地址来生成一个哈希值,返回哈希值是一个int类型的整数(返回的结果可能是一个负数)。
问题:
实例化出来的对象的地址值都不一样,则意味着实例化出来的对象调用hashCode()方法返回的结果都不相同。开发中,我们更多的是想通过对象的成员变量值来生成哈希值,那么该如何实现呢???
解决:
Object类提供的hashCode()方法满足不了我们的需求,那么我们在子类中就重写hashCode()方法即可。也就是在hashCode()方法中,根据对象的成员变量值来生成对象的哈希值,建议使用“alt + insert”快捷键来生成哈希值。
结论:
a)两个对象调用equals()方法返回的结果是true,则这两个对象调用hashCode()方法返回的结果相同。
–> 如果对象所对应的类没有重写equals()方法和hashCode()方法,则以上结论默认肯定满足。
–> 如果对象所对应的类重写了equals()方法和hashCode()方法,则以上结论也必须保证满足。
b)两个对象调用hashCode()方法返回的结果相同,则这两个对象调用equals()方法返回的结果未必是true。
–> 哈希算法是根据一定的规则来计算出来的结果,不同的两个对象得到哈希值可能相同,因此就有以上这个结论。
哈希算法的设计原则:不同对象计算出来的哈希值要尽可能的不同。
不同参数的hashCode代码如下:
1 | public static int hashCode(Object a[]) { |
1 | public static int hashCode(int a[]) { |
1 | public static int hashCode(boolean a[]) { |
还有很多不同参数的hash算法底层源码,再次不全部列举,但是可以看到都出现了31这个数字,为什么?
面试题1:在哈希算法中,为什么一定要使用31来做乘法运算???
a)因为31是一个质数,质数做乘法运算得到相同结果的概率较低。
31*5 –结果–> 155 –得到155的方式–> 31*5、5*31、1*315
30*5 –结果–> 150 –得到150的方式–> 30*5、5*30、5*5*6、5*6*5、5*2*15等等
b)因为31是一个质数,质数做乘法运算的效率非常非常高(位运算)。
公式:31*i 的位运算计算公式 –> (i << 5) - i
例如:31*5 –套计算公式–> (5<<5)-5 –结果–> 155
31*3 –套计算公式–> (3<<5)-3 –结果–> 93
面试题2:质数无穷无尽,为什么一定要选择31来做乘法运算???
公式:7*i 的位运算计算公式 –> (i << 3) - i
例如:7*5 –套计算公式–> (5<<3)-5 –结果–> 35
答案:数学家让我们使用31来做乘法运算的。
总结:
对java提供的类而言,默认已经重写了equals()方法和hashCode()方法,我们直接使用即可。
对自定义的类而言,那么我们就需要手动的重写equals()方法和hashCode()方法,然后再去使用。