博客
关于我
面试必问的HashMap-1.1:HashMap几个关键点分析
阅读量:670 次
发布时间:2019-03-15

本文共 1507 字,大约阅读时间需要 5 分钟。

HashMap的工作原理分析

HashMap并不算特别神奇,它的工作原理相对来说还是比较直接的。以下是我对HashMap的一些理解和分析。

数据结构方面

在Java中,常用的数据结构包括数组、链表和树。数组的查询效率很高,链表的新增效率又很高。HashMap的数据接口将这两种数据结构的优势结合了起来。

数组的实现

数组在Java中用数组表示,代码如下:

int[] aa = new int[16];

其中,16是2的4次方(1左移4位),这是数组的默认初始大小。这里用了位移运算来确定数组的大小,而不是直接写16,这样既方便又高效。

链表的实现

链表的实现方式类似于下面的代码:

public class Node {Object data;Node next;}

双向链表的实现方式类似于:

public class Node {Object data;Node previous;Node next;}

HashMap的独特之处

HashMap的独特之处体现在以下几个方面:

  • 数组与链表的结合
  • HashMap并不是单纯的数组或链表,而是两者的结合。数组用于存储元素,链表用于解决碰撞问题。

    1. 初始大小
    2. 数组的初始大小是16,这是2的4次方。这种选择有两个好处:

      • 16是二进制数,高效计算
      • 初始大小适中,避免内存浪费

      为什么不直接写16呢?因为底层都是二进制,位移运算效率更高。

      链表的长度限制

      链表的长度是有上限的。具体来说:

      • 如果链表长度超过8,就会转换为红黑树
      • 如果链表长度小于6,就会强制转换为红黑树

      这种设计目的是为了在高频率的删除操作后,避免链表过长导致效率低下。

      put方法分析

      put操作分为以下几个步骤:

    3. 调用putValue方法
    4. 计算key的hash值
    5. 根据hash值确定数组的位置
    6. hash函数的实现

      hash函数的实现非常关键。具体来说:

      int hash = key.hashCode();int hash = hash ^ (hash >> 16);

      这个hash函数的作用是将高16位和低16位进行异或运算,从而得到一个较为分散的hash值。

      为什么要用异或运算?

      异或运算(^)的特点是:

      • 与0异或结果不变
      • 两个位同时为1时,结果才为1

      这样可以充分利用高低位,提高hash值的分散性。

      数组存储位置的确定

      存储位置的计算公式是:

      int index = (n - 1) & hash;

      其中,n是数组的大小。n-1的作用是确保在碰撞发生时,仍然能得到有效的数组索引。

      为什么不直接用n?

      因为n是2的幂次方,n-1可以用来提取有效位。例如:

      n = 16 → n-1 = 15 → 0b1111

      这样无论hash值是什么,与运算n-1后,结果都落在0到15之间。

      这种方法比模运算(%)更高效,因为模运算需要进行额外的计算。

      链表转换与红黑树

      当链表长度超过8时,HashMap会将链表转换为红黑树。这是因为红黑树的查询效率更高。

      碰撞处理

      如果多个元素的hash值相同,就会形成碰撞。此时,HashMap会自动将链表转换为红黑树,或者在删除操作频繁时强制转换为链表。

      模运算与按位与运算

      模运算(%)和按位与运算(&)的区别在于:

      • 模运算是取余数
      • 按位与运算是只要有一个位为1,结果位就为1

      模运算效率较低,所以HashMap采用按位与运算来提高效率。

      总结

      HashMap的工作原理主要包括以下几个方面:

    7. 数组与链表的结合
    8. 高效的哈希函数设计
    9. 链表与红黑树的转换机制
    10. 碰撞处理策略
    11. 这种设计既保证了哈希表的平均时间复杂度,又在面对频繁碰撞时能够灵活调整结构,确保整体性能。

    转载地址:http://yxpmz.baihongyu.com/

    你可能感兴趣的文章
    Qt笔记——QLable+QPixmap图片缩放踩坑
    查看>>
    Qt笔记——foreach与forever
    查看>>
    QT程序怎么挪到Linux下,linux+Qt程序如何打包发布
    查看>>
    Qt知识:视图框架QGraphicsWidget详解
    查看>>
    SpringBoot中项目启动及定时任务缓存数据库常用数据至内存变量并转换后高频调用
    查看>>
    Qt知识: 画刷风格
    查看>>
    QT的OpenGL渲染窗QOpenGLWidget Class
    查看>>
    QT的C++程序加载动态链接库DLL(Linux下是so)的方式
    查看>>
    QT界面操作1:如何跟踪鼠标位置?
    查看>>
    Qt环境搭建(Visual Studio)
    查看>>
    QT点击"X"按钮,调用closeEvent()函数来实现调用特定事件(附:粗略介绍QT的信号与槽的使用方法)...
    查看>>
    QT样式表——url路径
    查看>>
    QT数据库(三):QSqlQuery使用
    查看>>
    QT教程5:消息框
    查看>>
    SpringBoot中集成阿里开源缓存访问框架JetCache实现声明式实例和方法缓存
    查看>>
    pom.xml中提示web.xml is missing and <failonmissingw>...
    查看>>
    Pomelo开发中Web客户端开发API简介
    查看>>
    QT教程2:QT5的体系构架
    查看>>
    PON架构(全光网络)
    查看>>
    PoolingHttpClientConnectionManager原理剖析
    查看>>