看了这篇文章, 可以了解 散列码和数组索引还不是一回事, 在hashmap中hashcode要先经过运算得到一个h,然后h&(length-1),这样才得到数组索引.
什么是hashcode
分析HashMap之前先介绍下什么Hashcode(散列码)。它是一个int,每个对象都会有一个hashcode,它在内存的存放位置是放在对象的头部(对象头部存放的信息有hashcode,指向Class的引用,和一些有关垃圾回收信息)。具体如何生成hashcode,这个相当复杂,由于我们的主题是“浅析”,所以不深入探讨。有个问题需要讲的是,如果在你的类中覆盖了Object的equals(Object)方法,那么你必须覆盖hashCode方法,不然,当你使用HashMap,HashSet,HashTable时会出现问题。具体原因下文会详细描述。
String类的hashcode
String类重写了Object类中的equals和hashCode方法,原因很简单,Object中的equals方法是指比较两个对象是不是指向同一个引用对象,而String类指需要比较内容相不相等就可以了。所以String覆盖了equals方法,同时覆盖了hashCode方法。这里需要提一下Object规范里规定:如果两个对象根据equals(Object)方式是相等的,那么这两个对象的hashCode一定要相等。
String中的hashcode算法很简单如下:
String类的hashcode
String中的hashcode算法很简单如下:
Val是一个char[],存放的是字符串的各个字符;Len是字符串长度;off从0开始;h从0开始。比如一个字符串“abc”(a的ascii码是97),它的hashcode算法是:
h = 31 * 0 + 97 ==> h = 97;
h = 31 * 97 + 98 ==> h = 3105;
h = 31 * 3105 + 99 ==> h = 96354;
所以“abc”的hashCode就是96354
存储方式
HashMap的存取
hash ^= (hash >>> 20) ^ (hash >>> 12);
int h = hash ^ (hash >>> 7) ^ (hash >>> 4);
为什么要经过这样的运算呢?这就是HashMap的高明之处。先看个例子,一个十进制数32768(二进制1000 0000 0000 0000),经过上述公式运算之后的结果是35080(二进制1000 1001 0000 1000)。看出来了吗?或许这样还看不出什么,再举个数字61440(二进制1111 0000 0000 0000),运算结果是65263(二进制1111 1110 1110 1111),现在应该很明显了,它的目的是让“1”变的均匀一点,散列的本意就是要尽量均匀分布。那这样有什么意义呢?看第3步。