HashMap的数据结构是散列表,首先通过hash值判定数据保存在数组中哪个节点,再通过链表把hash值相同的数据放到数组同一坐标。
关键点一 确定数据存放位置
##计算key的hash code java 7 版本
final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) { return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
位移计算目的是让key的hashcode分布更均匀,更松散的放到数组中。
##确定存放在数组的位置 java 7 版本
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16......static int indexFor(int h, int length) { return h & (length-1); }
我注意到Hashcode的初始化数组长度是16,这儿数字不是随意定的。我把indexFor方法分解成位运算会一目了然。 我们假设h=1,length是默认长度16。计算过程是: 16-1=15,位的变化是:10000 -> 1111。1 & 15 的二进制计算入下
0001 & 1111------ 0001
结果是1,作为对比,如果如果长度不是16而是14,那么14-1=13,1 & 13 的二进制计算入下
0001 & 1101------ 0001
结果一样,但是我们会发现,如果长度为14,“1101”的第2位的计算结果永远都会是0,也就是永远有一部分空间闲置不会被利用。
为了避免这种情况,所以初始化的长度是16(位2的n次方)。 如果我们要制定初始化大小,最好也遵循这个规律。