原文:http://blog.csdn.net/ghsau/article/details/21328203
前几天被人问到了hashcode如何实现,说实话,真的是没有自己写过,通常情况下都会通过IDE自动生成,惭愧。今天研究了下hashcode的生成原理,首先看一下String类中的hashCode方法:
- public int hashCode() {
- int h = hash;
- if (h == 0 && value.length > 0) {
- char val[] = value;
- for (int i = 0; i < value.length; i++) {
- h = 31 * h + val[i];
- }
- hash = h;
- }
- return h;
- }
核心的算法就是中间的for循环,假如字符串是"abcde",那最终的hash值应该是31(31(31(31a+b) + c) + d) + e,扩号展开为a*31^4+b*31^3+c*31^2+d*31^1+e*31^0,设字符串的长度为n,那最终的计算公式 为:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],这实际上就是31进制数转成10进制数的算法。那为什么要用31作为基数呢?
我想可能有几点原因:31首先是一个素数,与素数相乘运算后,能降低hashcode碰撞的概率;31其次是一个特殊的值(32-1),32的二进制是 100000,31的二进制是011111,31*N = N << 5 - N,运算速度会快。
普通类覆盖hashCode方法也可以使用类似的算法,如:
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((firstname == null) ? 0 : firstname.hashCode());
- result = prime * result
- + ((lastname == null) ? 0 : lastname.hashCode());
- result = prime * result
- + ((nickname == null) ? 0 : nickname.hashCode());
- return result;
- }
属性如果是引用类型,要与其hashCode运算,属性如果是byte、short、int类型,要与其值运算,属性如果是float、double、long,要经过特殊运算,可以参考对应封装类的hashCode方法实现。