首页 > 其他 > 详细

HashMap源码分析

时间:2016-02-22 16:43:54      阅读:208      评论:0      收藏:0      [点我收藏+]

 

1. 将loadFactor设置为0.75threshold设置为12,并创建一个大小为16Entry对象数组。

2. 可通过调用HashMap的另外2个构造器来控制初始的容量值及loadFactor,至于创建的Entry对象数组的大小,并非传入的初始容量值,而是采用如下方法来决定的:  

  public HashMap(int initialCapacity, float loadFactor) {
    // Find a power of 2 >= initialCapacity
    int capacity = 1;
    while (capacity < initialCapacity)
      capacity <<= 1;

    this.loadFactor = loadFactor;
    threshold = (int)(capacity * loadFactor);
    table = new Entry[capacity];
  }

  Capacity才是真正的创建的Entry对象数组的大小,即真实的Entry对象数组的大小应为大于initialCapacity2的倍数。

 

 3. put(Object key, Object value)

  对于keynull的情况,HashMap的做法为获取Entry数组中的第一个Entry对象,并基于Entry对象的next属性遍历,当找到了其中Entry对象的key属性为null时,则将其value赋值为新的value,然后返回。如没有key属性为nullEntry,则增加一个Entry对象,增加时为先获取当前数组的第一个Entry对象:e,并创建对象,keynullvalue为新传入的对象,next为之前获取的e,如此时Entry数组中已用的大小>=threshold,则将Entry数组扩大为当前大小的2倍,扩大时,对当前Entry对象数组中的元素重新hash,并填充数组,卒后重新设置threshold值。

  对于key不为null的情况,首先获取key对象本身的hashcode,然后再对此hashCodehash操作。

  Hash完毕后,将hash出来的值与Entry对象数组的大小减1的值进行按位与操作,从而得出当前key要存储到数组的位置。

  从这个过程可以看出,可能会出现不同的key找到相同的存储位置的问题,也就是数据结构中经典的hash冲突的问题了。

  下面是HashMap解决冲突的办法:

  在找到要存储的目标数组的位置后,获取该数组对应的Entry对象,通过调用Entry对象的next属性来进行遍历,寻找hash值和计算出来的hash值相等、且key相等或equalsEntry对象,如寻找到,则替换此Entry对象的值,完成put操作,并返回旧的值;如未找到,则往对应的数组位置增加新的Entry对象,增加时采取的方法和keynull的情况基本相同,只是它是替换指定位置的Entry对象,可以看出,Hash解决hash冲突采用的是链表的方式。

 

4. get(Object key):

  get的过程和put一样,也是根据key是否null来分别处理的。

  对于keynull的情况,则直接获取数组中第一个Entry对象,并基于next属性进行遍历,寻找keynullEntry对象,如找到则返回Entry对象的value值,如未找到,则返回null

  对于key为非null的情况,则对key进行hash和按位与操作,找到其对应的存储位置,然后获取此位置对应的Entry对象,基于next属性遍历,寻找到hash值相等,且key相等或equalsEntry对象,返回其value,若未找到,则返回null

 

5. remove(Object key):

  Remove的过程和get类似,只是在找到匹配的key后,如数组上的元素等于key,则将数组上的元素的值置为其next元素的值;如数组上的元素不等于key,则对链表遍历,一直到找到匹配的key或链表的结尾。

  

6. 总结:

  1. HashMap采用数组方式存储keyvalue构成的Entry对象,无容量限制
  2. HashMap基于key  hash寻找Entry对象存放到数组的位置,对于hash冲突采用链表的方式来解决
  3. HashMap在添加元素时,可能会扩大数组的容量,在扩大容量时需要重新计算hash,并复制对象到新的数组中
  4. HashMap时非线程安全的。在并发场景中,如果不保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU消耗到100%
  5. 在并发场景中,建议使用 ConcurrentHashMap

HashMap源码分析

原文:http://www.cnblogs.com/chy2055/p/5207413.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!