令人抓狂的HashMap - 长敏的小站

  1. 判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容;
  2. 根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向6,如果table[i]不为空,转向3;
  3. 判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向4,这里的相同指的是hashCode以及equals;
  4. 判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向5;
  5. 遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;
  6. 插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。

上源码

 1 public V put(K key, V value) {
 2     // 对key的hashCode()做hash
 3     return putVal(hash(key), key, value, false, true);
 4 }
 5
 6 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 7                boolean evict) {
 8     Node<K,V>[] tab; Node<K,V> p; int n, i;
 9     // 步骤①:tab为空则创建
10     if ((tab = table) == null || (n = tab.length) == 0)
11         n = (tab = resize()).length;
12     // 步骤②:计算index,并对null做处理
13     if ((p = tab[i = (n - 1) & hash]) == null)
14         tab[i] = newNode(hash, key, value, null);
15     else {
16         Node<K,V> e; K k;
17         // 步骤③:节点key存在,直接覆盖value
18         if (p.hash == hash &&
19             ((k = p.key) == key || (key != null && key.equals(k))))
20             e = p;
21         // 步骤④:判断该链为红黑树
22         else if (p instanceof TreeNode)
23             e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
24         // 步骤⑤:该链为链表
25         else {
26             for (int binCount = 0; ; ++binCount) {
27                 if ((e = p.next) == null) {
28                     p.next = newNode(hash, key,value,null);
                        //链表长度大于8转换为红黑树进行处理
29                     if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
30                         treeifyBin(tab, hash);
31                     break;
32                 }
                    // key已经存在直接覆盖value
33                 if (e.hash == hash &&
34                     ((k = e.key) == key || (key != null && key.equals(k))))
35                            break;
36                 p = e;
37             }
38         }
39
40         if (e != null) { // existing mapping for key
41             V oldValue = e.value;
42             if (!onlyIfAbsent || oldValue == null)
43                 e.value = value;
44             afterNodeAccess(e);
45             return oldValue;
46         }
47     }

48     ++modCount;
49     // 步骤⑥:超过最大容量 就扩容
50     if (++size > threshold)
51         resize();
52     afterNodeInsertion(evict);
53     return null;
54 }

二、HashMap之resize方法

final Node<K,V>[] resize() 大专栏  令人抓狂的HashMap - 长敏的小站class="o">{
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
          // 如果目前的容量已经达到最大容量,那就没必要扩容了
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // 容量threshold扩大一倍
        }
        else if (oldThr > 0) // 替换threshold
            newCap = oldThr;
        else {               // 初始化
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

—未完待续……

原文地址:https://www.cnblogs.com/liuzhongrong/p/12000081.html

时间: 2024-10-10 07:58:59

令人抓狂的HashMap - 长敏的小站的相关文章

网页设计中7个令人抓狂的错误

所有人都知道网页设计的重要性,糟糕的网页设计会给用户带来糟糕的体验,从而影响网页的流量,或是产品的销售.那么在设计网页的过程中,应该避免出现哪些错误呢? 1. 要求用户必须注册才能浏览网页内容 这种做法足以让用户立刻感到气愤不已.也许这样做能够让你获得一些注册用户,但是你失去的远比所得到的要多. 2. 忘记针对不同设备优化网页 要知道,现在很多用户都不再使用PC浏览网页了.因此在设计网页的时候,不要忘了针对智能手机.平板电脑等移动设备进行网页优化.你必须确保用户在任何设备上浏览你的网页时,都可以

python 令人抓狂的编码问题

#运行以下程序: #! /usr/bin/env python#coding=utf-8 file = open( 'all_hanzi.txt','wb' ) listhz = []n=0for ch in xrange(0x4e00, 0x9fa6): print unichr(ch), file.write( unichr(ch) )#此行出错.正确:file.write( unichr(ch).encode('gbk')) encode('gbk')将‘utf-8’编码的string编码

令人抓狂的Python redis和rediscluster驱动包的安装

本文环境:centos 7,Python3编译安装成功,包括pip3,然后需要安装redis相关的Python3驱动包,本的redis指redis包而非redis数据库,rediscluster类似. 先理清楚几个概念1,redis包更准确地说是redis-py包,是Python连接Redis的驱动文件,如果下载原始文件的话,文件名称就是redis-py-***.tar.gz2,rediscluster 包更准确地说是redis-py-cluster包,是Python连接Redis Cluste

为什么听有些人讲话让人抓狂

为什么光听有些人讲话,我就会抓狂——别人看来很普通的话.来自: 曳雨(仿佛一个世纪了……) 2011-08-31 16:05:42-----------------------------小时候看电视的时候就注意到这个问题了.就是有些电视里的人物或者主持人说某些话,我就忍不住必须换台,不然人就非常难受. 现实生活中,只要听到某些人讲某些话,或者打电话就会内心抓狂,手里很想抓个东西揉捏~~ PS:并不是这些人讲的所有话都会引起抓狂,有时候觉得也很正常,但在边上听他们讲话就会忍不住啊... 为什么啊

oracle 让人抓狂的错误之 null值 与 无值(无结果)-开发系列(一)

近期.在做开发.写存过的时候碰到一些问题,找了好长时间才发现原因.并且是曾经不知道的. 所以在这给记下来 给自己备忘和大家參考. 一 .null值 以下举个最简单的样例.寻常工作其中肯定比这个sql复杂的多,在这仅仅是把这个易错点呈现出来,他可能是一个复杂sql出错的小的 不easy被发现的一个问题. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGlhb2hhaTc5OA==/font/5a6L5L2T/fontsize/400/fill/I0JB

互联网公司的产品经理是如何让程序猿抓狂的

随便写写,就当吐槽和搞笑吧 1 产品经理:就是改个界面嘛,应该很快的哦! (程序猿:你行你来改啊!) 2 产品经理:这个功能我们公司的某某产品已经有了,搬过来就好了,很快的啦! (程序猿:快你妹啊,架构和底层类都不一样,好吗?界面风格和现有的也不搭啊!) 3 产品经理:(to iOS客户端开发)做成和Android一样就好啦 (程序猿:和Android一样是什么样......) 4 产品经理:和微信一样...和淘宝一样...和某某产品一样.... (程序猿:..... ) 5 产品经理:其他组已

oracle开发系列(一)让人抓狂的错误之 null值 与 无值(无结果)

最近,在做开发.写存过的时候碰到一些问题,找了好长时间才发现原因,而且是以前不知道的.所以在这给记下来 给自己备忘和大家参考. 一 .null值 下面举个最简单的例子,平常工作当中肯定比这个sql复杂的多,在这只是把这个易错点呈现出来,他可能是一个复杂sql出错的小的 不容易被发现的一个问题. 上面是一个很简单表的所有数据.area_num 区域编码 area_name 区域名称 delflag 有无效标识 1有效 0无效(其中淮北 和宣城的delflag为null). 现在想找出有效的那些区域

IT技术 | 让程序员抓狂的排序算法教学视频

点击「箭头所指处」可快速关注传智特刊微信号:CZTEKAN 原文地址:http://mp.weixin.qq.com/s?__biz=MjM5OTM4NDMyMg==&mid=200568203&idx=2&sn=cddc0bf4f5512c04e9c4de2705e2e68e#rd 罗马尼亚是一个爱跳舞的民族,如果你看过罗马尼亚老电影<奇普里安.博隆贝斯库>,那欢快悠扬的舞曲之炽热呵,非把你融化不可! 罗马尼亚人爱跳舞,不仅体现在电影和节日中,你会发现舞蹈无处不在,即

vi与vim的抓狂

1. vi和vim的关系:    vim可以理解是vi的升级版,支持shell script编程:    vi存在原因:所有Unix Like系统均内建vi编辑器,同时个别工具会主动呼叫vi,如crontab.    2. 关于vi的三种模式:    一般模式    编辑模式    命令模式 3. vi的一般模式命令:    1)光标移动:        单个字符:h(左).l(右).k(上).j(下):        行头:^/0/Home,行尾:$/End:        多行:nk.nj.