HashMap扩容机制以及和HashTable、ConcurrentHashMap理解

Java集合是一个非常重要的知识点,其中的HashMap和HashTable以及ConcurrentHashMap更是重中之重,首先先聊一下一道常见的面试题,HashTable和HashMap的区别是什么? 简单回答的话:

1、HashTable是线程安全的,HashMap是线程不安全的。
2、HashTable由于线程安全问题,所以效率会比HashMap慢。
3、HashTable是不允许null值存在的,相反HashMap则是可以允许null值存在的。
这样答下来的话,面试题基本算是过了。但是这时候面试官再问,有没有一种类是HashTab和HashMap的结合体,既是线程安全的又和HashMap类似呢?答案肯定是有的,这个时候我们就要扯到ConcurrentHashMap了。
但是首先,我们先了解一下HashMap的底层扩容机制。
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第1张图片

1、首先我们先看看HashMap的三个常量

首先第一个代表的意思就是HashMap的初始容量,默认是16。
第二个 MAXIMUM_CAPACITY 代表的是最大容量就是 1<<30 就是2的30次方 也就是 1073741824。
第三个 DEFAULT_LOAD_FACTOR 代表的是负载因子 0.75,这个在后面的扩容会用到。

2、接下来聊一下HashMap的put操作

在这里插入图片描述
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第2张图片

1、首先第一次 put一个新的值进来的时候会将传进来的值算出hash值,具体的算法就是键的hashCode()方法与高位16进行异或运算得到hash值。
2、然后我们继续看putVal()方法
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第3张图片首先判断数组中是否已经创建,此时还未创建数组,所以此时调用resize() 方法设置初始容量,如果未设置初始容量,那么默认的初始容量就是16,我们上面有提到过。(注意容量只能为2的倍数,即使输入的不是2的倍数也会自动转换)。
如果这个时候我们再次put一个新的值进来,并且让这两个键的hashCode相等,那么这两个元素会被存储在同一个链表中,进入putVal()方法后,上面的第一个if语句为false,因为已经初始化了数组,第二个if也是false,因为当前链表下的头元素已经存在,它会进入if语句的分支else语句
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第4张图片
第一个if语句判断链表中头元素与当前插入的元素是否是同一个元素(hash()方法与equals()方法比较)
在这里插入图片描述这个else if是判断当前数组的节点是链表还是红黑树,如果是红黑树,就按红黑树的添加方式添加。
在这里插入图片描述继续往下看
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第5张图片可以看到,这是一个死循环,如果想要结束这个死循环,只有两种方式。
第一种: 链表中没有找到与当前添加的的元素相同的元素的话,这个时候就会进行尾插法,直接在末尾插入这个元素,然后进行if判断添加这个元素前,链表的长度是否达到了8,如果达到了,那么就会进行treeifyBin这个方法
在这个方法中,如果数组容量小于64时,数组容量会调用resize()方法扩容,扩容为当前的两倍。
在这里插入图片描述第二种: 如果找到了与添加的元素相同的元素,那么会直接跳出循环,进入下面这个if中,覆盖原有的value值
HashMap扩容机制以及和HashTable、ConcurrentHashMap理解_第6张图片之后再更新数组的元素个数,超过了就进行扩容,同样还是扩容为两倍。
在这里插入图片描述

你可能感兴趣的:(HashMap,java,面试,数据结构)