更新 对于HashMap的一些疑问.md

This commit is contained in:
小柒2012
2018-08-30 17:34:20 +08:00
parent 7e0a8c3ade
commit db705f8b4a

View File

@@ -7,7 +7,7 @@
![输入图片说明](https://images.gitee.com/uploads/images/2018/0830/173144_4d97d72f_87650.png "2.png")
一、HashMap的resize过程是什么样的
#### 一、HashMap的resize过程是什么样的
HashMap在put的时候会先检查当前数组的length,如果插入新的值的时候使得length > 0.75f * sizef 为加载因子可以在创建hashMap时指定的话会将数组进行扩容为当前容量的2倍。 扩容之后必定要将原有hashMap 中的值拷贝到新容量的hashMap 里面HashMap 默认的容量为16加载因子为0.75 也就是说当HashMap 中Entry的个数超过 16 * 0.75 = 12时, 会将容量扩充为 16 * 2 = 32然后重新计算元素在数组中的位置这是一个非常耗时的操作所以我们在使用HashMap的时候如果能预先知道Map中元素的大小预设其大小能够提升其性能。 resize代码
@@ -94,7 +94,7 @@ e = next;
这是1.7中的代码1.8中引入了红黑树的概念,代码会相对复杂一些。
二、HashMap在扩容的时候为什么容量都是原来的2倍即容量为2^n
#### 二、HashMap在扩容的时候为什么容量都是原来的2倍即容量为2^n
HashMap 在计算数组中key的位置时使用的算法为
/* * Returns index for hash code h. */
@@ -108,23 +108,23 @@ H & (length -1) hash & table.length-1 4 & (15 - 1) 0100 & 1110 = 0100 5 & 15
我们能够看到在容量为16时进行indexFor操作之后获得相同结果的几率要比容量为15时的几率要小这样能够减少出现hash冲突的几率从而提高查询效率。2 ^ n是一个非常神奇的数字。
三、put时出现相同的hashcode会怎样
#### 三、put时出现相同的hashcode会怎样
hashMap 里面存储的Entry对象是由数组和链表组成的当key的hashcode相同时数组上这个位置存储的结构就是链表这时会将新的值插入链表的表头。进行取值的时候会先获取到链表再对链表进行遍历通过key.equals方法获取到值。hashcode相同不代表对象相同不要混淆hashcode和equals方法 所以声明作final的对象并且采用合适的equals()和hashCode()方法的话将会减少碰撞的发生提高效率。不可变性使得能够缓存不同键的hashcode这将提高整个获取对象的速度使用StringInterger这样的wrapper类作为键是非常好的选择。
四、什么是循环链表?
#### 四、什么是循环链表?
HashMap在遇到多线程的操作中如果需要重新调整HashMap的大小时多个线程会同时尝试去调整HashMap的大小这时处在同一位置的链表的元素的位置会反过来以为移动到新的bucket的时候HashMap不会将新的元素放到尾部为了避免尾部遍历这时可能会出现A -> B -> A的情况从而出现死循环这便是HashMap中的循环链表。 所以HashMap 是不适合用在多线程的情况下的可以考虑尝试使用HashTable 或是 ConcurrentHashMap
五、如何正确使用HashMap提高性能
#### 五、如何正确使用HashMap提高性能
在设置HashMap的时候指定其容量的大小减少其resize的过程。
六、JDK1.8对HashMap进行了哪些优化
#### 六、JDK1.8对HashMap进行了哪些优化
jdk1.8在对hash冲突的key时如果此bucket位置上的元素数量在10以下时还是和原来一样使用链表来进行存储这时寻址的时间复杂度为O(n),当元素数量超过10时使用红黑树进行代替这时寻址的时间复杂度为O(n)
七、HashMap 与 HashTable、ConcurrentHashMap的区别
#### 七、HashMap 与 HashTable、ConcurrentHashMap的区别
1.HashTable的方法是同步的在方法的前面都有synchronized来同步HashMap未经同步所以在多线程场合要手动同步
2.HashTable不允许null值(key和value都不可以) ,HashMap允许null值(key和value都可以)。