HashMap
hashmap的底层数据结构
Hashmap底层是由数组和链表结合实现的
参考容量(capacity)
用来作为创建map对象中Node[]数组的初始长度(容量)的参考,默认为16。
可以自己指定长度,指定方式为:Map map = new HashMap<>(capacity);//capacity的值就是你要指定的长度
扩容阈值(threshold)和负载因子(loadFactor)
hashmap在新增元素的过程中,如果达到扩容阈值,就会扩大Node[]数组的长度
其默认值为:参考容量 * 负载因子
而负载因子的默认值为0.75,可以修改但是不建议修改。
求Hash值
hashmap内部有一个机制:创建map对象中Node[]数组的初始长度必须要是2的n次方(原因在2.(3)),当你设置长度是23的时候,hashmap会把初始长度设置成32。因为23在16(2的4次方)到32(2的5次方)之间,取最大的数32。
这样做的好处是
直接算出来的hash值可能非常大,不可能直接当作数组下标的。对此hashmap的设计者有自己的解决方案:求余
也就是:index = hash值 % 数组长度
这样的话index的值永远都在数组长度之内,也就可以作为数组下标了
但是这样做有一个缺点:效率低,于是hashmap的设计者把求余改成了一个效率更高的运算:减一与运算
也就是:index = hash值 & (数组长度-1)
但是Node[] 数组的长度必须是2的n次方才行!
HashMap的Put方法
数组扩容的过程
创建一个新的数组,其容量为旧数组的两倍,并重新计算旧数组中结点的存储位置。结点在新数组中的位置只有两种,原下标位置或原下标+旧数组的大小。
HashMap & ConcurrentHashMap 的区别
除了加锁,原理上无太大区别。另外,HashMap 的键值对允许有null,但是ConCurrentHashMap 都不允许。
Java 中的另一个线程安全的与 HashMap 极其类似的类是什么?同样是线程安全,它与 HashTable 在线程同步上有什么不同?
ConcurrentHashMap 类(是 Java并发包 java.util.concurrent 中提供的一个线程安全且高效的 HashMap 实现)。
HashTable 是使用 synchronize 关键字加锁的原理(就是对对象加锁);
而针对 ConcurrentHashMap,在 JDK 1.7 中采用 分段锁的方式;JDK 1.8 中直接采用了CAS(无锁算法)+ synchronized。