1 HashMap的数据结构
数据结构中有两种基本的存储结构,数组和链表,这两个基本是就是两个极端
a,数组
数组的存储结构是连续的,内存浪费严重,空间复杂度高,但查找操作的时间复杂度很低,为O(1),所以数据:寻址容易,add()和delete()困难
b,链表
链表的存储结构是离散的,内存浪费低,(我感觉这可以降低内存中的碎片生成,操作系统里看到的东西,不知道这样分析对不对)但查找操作的时间复杂度达到O(N),所以链表:寻址困难,add()和delete()容易
HashMap用“拉链法”实现出来的下图这样,这货是杂交出来的集大成者--链表的数组
![复习一下hashMap 复习一下hashMap](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
![复习一下hashMap 复习一下hashMap](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
这些数据如何存储到数组中的呢,可以通过hash(key)%length来得出在数组中的具体位置,如何图中数组index为12的几个entry,他们的中的key的hash(key)都是12
HashMap内部有一个entry的内部类,重要的属性包含key,value,next,这是一个HashMap键值对的基本bean,所以上图中数组其实就是一个entry[],map中的内容对放在entry[ ]中
至于 transient 的意思 附个链接http://www.cnblogs.com/lanxuezaipiao/p/3369962.html,好像是数据序列化时用的,还没细读
- staticclass Entry implements Map.Entry {
-
final Kkey; -
Vvalue; -
Entrynext; -
inthash;
-
-
Entry(inth, K k, V v, Entry n) { -
value = v; -
next = n; -
key = k; -
hash = h; -
}
这里注意一点,当两个hash(key)&length结果一下时,会加入到上图的那个链表中,新来的加入到表头,最先来的实际是在最后的位置上。
还有一个要注意,hash(key)和hashcode(key)好像不是一回事,代码如下
-
-
final int hash(Object k) { -
int h =hashSeed; -
if (0 != h&& k instanceof String) { -
returnsun.misc.Hashing.stringHash32((String) k); -
}
-
h ^=k.hashCode();
-
// Thisfunction ensures that hashCodes that differ only by -
//constant multiples at each bit position have a bounded -
// numberof collisions (approximately 8 at default load factor). -
h ^= (h>>> 20) ^ (h >>> 12); -
return h ^(h >>> 7) ^ (h >>> 4); -
}
2
hash算法
我们要在hashmap中找到某个value,需要根据key的hash值来找到对应数组的位置,怎么计算这个位置就是hash算法,“拉链法”实现的hashmap是由数组和指针杂交的,我们需要让他们分布的更加均匀些,尽量每个位置对应的元素只有一个,这样找到数组的位置是直接就能得到value了,不用去遍历链表,现在问题来了,怎么办?
首先想到的是hashcode(key)%length,这样分布的均匀些,但取”模“运算消耗还是很大,java中是这样实现的
-
static int indexFor(int h, int length){ -
// assertInteger.bitCount(length) == 1 : "length must be a non-zero power of2"; -
return h& (length-1); -
}
取得key的hashcode然后和数组长度&一下,简直牛逼!!!这就可以很清楚的看出来为什么hasmap的初始数组长度要是2的幂了
看到了吧这样非常有效的降低了发生碰撞的可能性,分布也就更加均匀,效率提升不小吧!
所以Java中最好指定2的幂为数组的大小,就算你不指定,Java也是按照比指定值大切最接近指定值得2的幂那个值来做初始大小的---指定值为3,Java中就给你改成4了
- int capatity = 1;
- while(capatity
- capatity <<=1;
- }