JAVA - HashMap特点及小结

HashMap

HashMap实现了Map接口,用于存储K,V键值对的集合类。
主要特征包括:Key可存NULL、无序、线程不安全、 底层使用了数组+链表+红黑树的结构。

特点

在阅读源码基础上,查阅并结合其他文章资料,以介绍+提问的形式,列出HashMap以下常见特点若干项。

  1. HashMap存储单元类型。
    hashMap内部使用Node类型对象来保存内容。
    Node类型中包括hash、key、value、next四部分。

  2. HashMap的存储结构。
    HashMap的存储结构中使用了Node类型的数组、单链表、和红黑树。
    单链表和红黑树是用来处理哈希冲突时的节点存储。

  3. HashMap初始容量、最大容量、负载因子、如何扩容。
    初始容量:默认为16。
    最大容量:为2^30。
    指定容量时,使用tableSizeFor方法向上取值,且未2的幂次方,比如:30向上取值为32。
    负载因子默认为0.75,扩展因子*容量为扩容阈值,当达到扩容阈值时,容量扩为原来的2倍。

  4. HashMap put 插入过程。
    简单划分为以下4个过程:

    • 初始化检查
      如果数组为空,则初始化数据。

    • 确定插入位置
      散列计算确定插入的哈希桶位置,采用Hash值对N取模【 hash & (N-1)】,确定哈希桶的位置。

    • 哈希碰撞、处理阶段
      如果要插入的哈希桶为空,则直接插入节点。
      如果哈希桶有值了,则判断是哈希冲突还是重复插入。
      如果是重复插入,则更新插入的值。
      如果是哈希冲突,则采取处理哈希冲突的策略,策略包括拉链法和构建红黑树。

    • 容量检查、扩容
      插入节点后,如果超出了阈值【大小*负载因子】,进行Resize扩容操作。

  5. HashMap的扩容过程。
    新数组扩容为原来数组的两倍。
    将原来数组中节点拷贝到新数组中。如果:

    • 原节点是普通节点,则用该节点哈希值取模,确定在数组中的位置,插入。
    • 原节点是链表节点,则将整个链表拷贝到新数组中。
    • 原节点是红黑树,用 split方法将红黑树拆成两个链表,判断每个链表的长度是否小于等于 六,如果是就将 TreeNode 转换成桶内链表,否则再转换成红黑树。
  6. HashMap插入数组的位置如何确定。
    采用Hash值对容量N取模,模得到的值即是下标值。
    在HashMap中采用位运算进行取模:(n-1) & hashCode()。

  7. HashMap中如何判断哈希冲突。
    当两个Key的HashCode相同,且Key不同时,认定为冲突。

  8. HashMap中如何处理哈希碰撞。
    当发生哈希碰撞时,首先会采用拉链法处理冲突。
    当哈希桶中拉链长度小于等于8时,会采用尾插法插入节点,形成一个单向链表。
    当拉链长度大于8,且数组容量【哈希桶】小于64时,会进行扩容,不会进行树化。
    当拉链大于8且数组容量大于等于64时,会将链表转换为红黑树。

  9. HashMap中取哈希码的逻辑是什么?为什么这样做 ?
    HashMap取哈希码采用将高16位与低16位进行异或运算。(h = key.hashCode()) ^ (h >>> 16);
    这样的好处是将高位的特征保留到低位中,使低16位相同,高16位不同的32位数在取模时不会得到相同结果,增加随机性、减少冲突。

  10. Hash方法取哈希值为什么要使用异或运算 ?
    异或运算保证了32位中只要有1位发生变化,高低16位异或得到的哈希值就会改变!!!
    与、和运算达不到这样的效果!

  11. 从链表到红黑树转换的值为什么是8 ?
    当长度为8的时,红黑树的平均查找长度是Log(8) =3;链表的平均查找长度为8/2 =4,所以有必要从链表转为红黑树。

  12. HashMap的容量值为何要设置成2的幂次方 ?
    为了便于使用位运算对Hash值取模。例如:在JDK 1.0时 HashTable的取模运算方法是 hash % N ;而在HashMap中,将N固定为2的幂次方时,可以采用 hash & (N-1) 算法完成取模操作,加快运算速度。

  13. HashMap是否线程安全 ?
    HashMap线程不安全,若要保证线程安全,可以使用ConcurrentHashMap、或使用Collection中synchronizedMap的包装器进行包装。

  14. JDK 1.7和1.8中HashMap的主要区别?
    JDK 1.8引入并使用了红黑树。
    JDK 1.8采用了尾插法插入节点。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值