zoukankan      html  css  js  c++  java
  • HashMap

    1.  我们知道Map是一个 key-val 的集合,HashMap是基于Hash表的Map接口的非同步实现。

    2.  HashMap的基本数据结构是数组和链表。(借鉴一张图)

       

       HashMap的存储原理:声明一个下标范围比较大的数组来存储元素,另外设计一个哈希函数获得每一个元素的Key(关键字)的函数值(即数组下标,hash值)相对应,数组存储的元素是一个Entry类,这个类有三个数据域,key、value(键值对),next(指向下一个Entry)。 当两个key通过哈希函数计算相同时,则发生了hash冲突(碰撞),HashMap解决hash冲突的方式是用链表。

       例如, 第一个键值对A进来。通过计算其key的hash得到的index=0。记做:Entry[0] = A。 
       第二个键值对B,通过计算其index也等于0, HashMap会将B.next =A,Entry[0] =B, 
       第三个键值对 C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方事实上存取了A,B,C三个键值对,它们通过next这个属性链接在一起。所以当hash冲突很多时,HashMap退化成链表。

    3.  HashMap的存储过程

       先判断键值对数组table[i] 是否为空否则进行扩容操作(resize());

       根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加到最后一步,如果table[i]不为空进行下一步; 

       判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则进行下一步,这里的相同指的是hashCode以及equals; 

       判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则进行下一步; 

       遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; 

       插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。

       HashMap取值过程:

       先通过key值进行哈哈希函数的运算得到hash值;

       调用getNode(),得到桶号;

       在桶里面找元素和key值相等的即可,未找到返回空。

    4.  HashMap的初始化容量为什么为2的次幂?

       因为在get()方法中,获得元素的位置是通过(length- 1) & h 来得到的,其中 h:为插入元素的hashcode length:为map的容量大小。如果length为2的次幂 则length-1 转化为二进制必定是11111……的形式,在于h的二进制与操作效率会非常的快,而且空间不浪费。如果是其他的话,空间不够,碰撞的几率变大,查询变慢,空间会浪费。  

    5.  为什么HashMap是非线程安全的?

       首先我们知道为了减少冲突,我们需要时刻留意当前的size是否太大,检查是否需要扩容,一旦超过设定的threshold,那么就要重新增大数组尺寸,此时所有元素都需要重新计算应该放置的下标。同时HashMap在扩容的时候,是通过重新创建一个新的hash表,把原来旧数组中的Entry一个个迁移到新数组的,注意一点就是计算在newTable中的位置,原来在同一条链上的元素可能被分配到不同的位置。

       单线程的情况resize()是没有问题的,但是多线程的时候就可能会出现形成环形链表的情况,导致扩容失败。具体详细的图可以看https://blog.csdn.net/andy_budd/article/details/81413464

    6.  HashMap和HashTable的区别:

       HashTable 是不能接受NULL,NULL值组合的,而HashMap可以。(因为HashMap做了对应的NULL值处理,会把NULL值的键值对放到hashcode 为0 的链表里面)。

       HashTable是线程安全的,HashMap是线程非安全的。因为HashTable是synchronized,要想是HashMap线程安全Map m = Collections.synchronizeMap(hashMap);

  • 相关阅读:
    Java基础——clone()方法浅析
    Unity shader error: “Too many texture interpolators would be used for ForwardBase pass”
    ar 解压一个.a文件报错: xxx.a is a fat file (use libtool(1) or lipo(1) and ar(1) on it)
    How to set up "lldb_codesign" certificate!
    Unity-iPhone has Conflicting Provisioning Settings
    ETC1/DXT1 compressed textures are not supported when publishing to iPhone
    Xcode 提交APP时遇到 “has one iOS Distribution certificate but its private key is not installed”
    XCode iOS之应用程序标题本地化
    苹果电脑(Mac mini或Macbook或iMac)恢复出厂设置
    Unity 4.7 导出工程在XCode10.1上编译报错
  • 原文地址:https://www.cnblogs.com/jkzr/p/10504548.html
Copyright © 2011-2022 走看看