HashMap

hashmap的底层数据结构

Hashmap底层是由数组和链表结合实现的

java 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方法

java HashMap 初始化 入参 hashmap初始化过程_链表_02

数组扩容的过程

创建一个新的数组,其容量为旧数组的两倍,并重新计算旧数组中结点的存储位置。结点在新数组中的位置只有两种,原下标位置或原下标+旧数组的大小。

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。