1.以String类的hashCode方法为例:
//jdk1.7源码
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; }
以字符“a”为例,字符‘a’的ascii码为97,计算后的h = hashCode为31*0+97,hash=h=97;
以字符串“abc”为例,"h = 0" ==> "h = 31*0+97 = 97" ==> "h = 31*97+98 = 3105" ==> "h = 31*3105 + 99 = 96354",即字符串“abc”的hashCode值为96354。
2.计算原理:
String的hasCode函数以31为倍数,是因为31的二进制全是1,可以有效的离散数据,同时前面的字段权重大,这样的好处是前缀相同的字符串的hash值都落在临近的区间,hash数组比较小,占用内存较小,存取效率也高。
3.hash冲突:
以HashMap为例,在存取键值对时,会对key键进行hash算法,如果key为字符串,则调用String的hashCode方法,在数据量大的时候会出现计算后的hashCode相同的情况,即为hash冲突。
解决方案:HashMap的解决方案是通过链表策略解决,即hashCode相同的键值对存放到hash数组的同一个下标的 Entry链表中;如果存储位置下标对应的值为null,则创建Entry并将键值对放入其中,再将Entry放入当前下标对应的空间,如果同一下标已经存在Entry,则存放到该Entry链表的下一个节点上,以此类推。
除此之外hash冲突的解决方案还有:开放地址法(冲突后寻找数组中下一个空位置),多重散列法(冲突后使用不同的hash函数,再次散列,直到不冲突),公共溢出区法(冲突后将冲突的的键值对插入到公共溢出表)。