HashMap学习总结
HashMap
1.在创建map集合对象的时候,在jdk1.8之前,构造方法中创建一个长度是16的Entry[] table一维数组来存储键值对数据。而在jdk1.8之后是在第一次调用put方法时创建的Node[] table用来存储键值对数据。
2.假设向哈希表中存 柳岩-18 数据,根据 柳岩 调用String类中重亏之后的hashcode()方法计算出值,然后结合数组长度采用某种算法计算出向Node数组中存储数据的空间的索引值。如果计算出的索引(空间没有数据,则直接存 柳岩-18存储到数组中。举例:计算出的索引是3
面试题:哈希表底层采用何种算法计算hash值?还有哪些算法可以计算出hash值?
底层采用的key的hashcode方法的值结合数组长度进行无符号右移(>>>),按位异或(^) 按位与(8计算出索引1。还可以采用:平方取中法,取余数,伪随机数法10%8–)2 11%8—》3 其他计算方式相率比较低.而位运算效率要高。
3.向哈希表中存储数据刘德华-40,假设刘德华计算出的hashcode方法结合组长度计算出的索51值也是3, 那么此时数组空间不是null,此时底层会比较柳岩和刘德华的hash值是否一致,如果不一致.则在此空间上划出一个节点来存储键值对数据刘德华-40.这种方式称为拉链法
4.假设向哈希表中存储数据柳岩-20,那么首先根据柳岩调用hashCode方法结合数组长度计算出泰号1肯定3,此时比较后存储的数据柳岩和己经存在的数据的hash值是否相等,如果hash值相等,此时发生哈希碰撞。那么底层会调用柳去所属类5tring中的equals方法比较两个内容是否相等:相等:则将后添加的数据的value霞盖之前的value;不相等:那么我续向下和其他的数据的key.
扩容:初始容量为16,加载因子为0.75,当hashmap中元素超过容量*0.75(12)时(不是数组个数沾满12格),就会进行扩容,每次扩大为原来的两倍。
(为什么是0.75:因为加载因子过高就会导致cpu压力增加,性能降低,过低则会导致浪费内存,因为空格子也会占用内存。所以通过计算出来0.75最优。)
为什么创建的数组长度必须是2的n次幂的长度?
在计算hash值的时候,需要通过 hashcode值 & (数组长度 - 1) 计算出hash值,数组长度如果是2的n次幂的话,会让数据分布均匀,减少哈希碰撞。
如果不是2的n次幂的话,会浪费大量的空间。如果不考虑,则直接取余即可。
为什么集合中继承了AbstractMap
创始人的失误。
HashMap,HashTable,ConcurrentHashMap的区别:
Table底层是数组+链表实现,是线程安全的,他是不允许存空值的,在修改数据时会锁住整个hashtable,效率低,Hashmap是线程不安全的,可以存空值的,Map是异步执行,table是同步执行,所以在单线程中,map比table速度快,concurrenthashmap底层是数组和链表,是线程安全的,把整个map分为几段,使用锁分离技术,并发进行,在多线程环境下,效率比hashtable高。比hashmap线程安全,不会数据丢失。
HashMap多线程操作会导致死循环(导致get无限循环,具体表现为CPU使用率为100%):
高并发下rehash(扩容后数组从旧的表移动到新表中过程)会造成元素之间形成一个循环链表,1.8后解决了,但是有可能会有数据丢失,并发环境下使用concurrenthashmap。



