1:HashMap的基本原理,内部数据结构,put操作的整体流程,是否线程安全以及为什么?jdk8对hashmap做了哪些优化?

  • HashMap默认长度是16,并且每次自动扩展或手动初始化时,长度必须是2的幂次方。
HashMap的基本原理
  • 通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。
内部数据结构
  • 数组
    数组存储区间是连续的,占用内存严重,故空间复杂度大。但数组的二分查找时间复杂度小,为O(1);
    数组特点:寻址容易,插入和删除困难;
  • 链表
    链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。
    链表特点:寻址困难,插入和删除容易。
  • 哈希表
    那么我们综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构,这就是哈希表
    哈希表有多种不同的实现方法,HashMap则使用的是拉链法,也叫作**【链地址法】**
put操作的整体流程
  • 对key的hashCode()做hash,然后再计算index; index = HashCode(Key) & (Length - 1)
  • 如果没碰撞直接放到bucket里;
  • 如果碰撞了,以链表的形式存在buckets后;
  • 如果碰撞导致链表过长(大于等于TREEIFY_THRESHOLD),就把链表转换成红黑树;
  • 如果节点已经存在就替换old value(保证key的唯一性)
  • 如果bucket满了(超过load factor*current capacity),就要resize。
HashMap是否线程安全—不安全
jdk8对HashMap做了哪些优化
  • 当链表长度太长(默认超过8)时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入、删除、查找等算法
红黑树的特性和优势
  • 首先,理解二分查找树(二分查找树具备的特性)
  1. 左子树上所有结点的值均小于或等于它的根节点的值
  2. 右子树上所有结点的值均大于或等于它的根节点的值
  3. 左,右子树也分别为二叉排序树
  4. 采用了二分查找的思想,查找所需的最大次数等同于二叉查找树的高度,在插入结点的时候也是利用类似的方法,通过一层一层比较大小,找到新节点适合插入的位置
  • 二分查找树的缺陷
  1. 二分查找树可能退化成链表的形式,这种情况下二分查找数的查找时间度又变为O(n)了