对于jdk1.7来说HashMap采取的是数组+链表的形式来进行储存的,但是为啥是采取数组+链表呢,我理解的原因是:
首先得了解到数组是一块连续的空间、链表是不连续的。之所以是数组+链表是为了更少的开辟空间,提高效率
对于key来说,我们首先要将key的ascii码进行hash,获取到的值作为数组的下标进行储存,当然会存在哈希值一样的(因为数组会被直接盖住),这个时候就会进行链表的头插法,数组的长度初始值为16每次扩容2,不过呢在扩容之前有还有一个负载因子,代表了table的填充度有多少,默认是0.75。
在hashmap源码中有一段网址,大概意思就是说HashMap遵循Poisson_distribution,Poisson_distribution这就是泊松定律呀,
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
负载因子为啥是0.75而不是1或者0.5呢?
答案:因为是0.5的时候,数组容量达到一半就开始扩容,hash冲突就会少一点,链表查找就会快一点,可是消耗的空间就会多一倍呀!!这就是牺牲空间来保证时间的做法。当负载因子为1的时候,这种情况下,虽然空间变小了,但是需要做查询的时间就高类呢!!!这就是牺牲了时间来保证空间的利用率。所以说呢就是取一个折中的办法,就只能是0.75了(其实还是根据泊松定律来得)
对于jdk1.8数组+链表+红黑树
为什么有了红黑树还要链表?
答案:先看下面这段源码,他是说因为树节点所占空间是普通节点的两倍,所以只有当节点足够多的时候,才会使用树节点。也就是说,节点少的时候,尽管时间复杂度上,红黑树比链表好一点,但是红黑树所占空间比较大,综合考虑,认为只能在节点太多的时候,红黑树占空间大这一劣势不太明显的时候,才会舍弃链表,使用红黑树。还有就是红黑树查询快,插入慢。
* Because TreeNodes are about twice the size of regular nodes, we
* use them only when bins contain enough nodes to warrant use
* (see TREEIFY_THRESHOLD).
链表转化为红黑树的条件是节点个数超过8
static final int TREEIFY_THRESHOLD = 8;
红黑树转化为链表的条件是节点个数为6
static final int UNTREEIFY_THRESHOLD = 6;
为什么是这两个数字呢,其实上面已经说过了, 链表转化为红黑树还是红黑树转化为链表取这两个数字都是为了提高速率,那为什么是这两个数字呢,还是因为一个那一个概率论公式泊松定理得到的(emmm,具体就不分析了)