当前位置: 首页 > news >正文

Jdk1.8-HashMap put() 方法tab[i = (n - 1) hash] 解惑

读过HashMap源码的同学对下面这段应该都不陌生,之前博主也读过,但是只是浅尝即止,这次有时间看了一下,发现put方法有一段不是很清楚,就是
if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null);这段代码,其中获取了当前table数组的最大下标与hash(key)进行按位与操作,上网也查了一下,没有找到相关的,稍后自己回忆了一下按位与操作,其实很容易懂:
就是最简单的如果没有Hash冲突就将Node对象创建出来,放到table数组中,其中就利用了按位与操作的一个特点,必须两个位都为1,才是1,那么也就是说,如果数组最大下标为15,那么不管Hash(key)是多少都不会大于15,也就不会数组越界

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

为什么不用取余操作?
首先取余操作,

  1. hash计算的值一般都会很大,那么取余操作分部的话 基本都会落到最后一个桶里

  2. 取余的效率没有位操作快,一般认为,Java的%、/操作比&慢10倍左右,因此采用&运算而不是h % length会提高性能。

  3. 因为HashMap中的容量都是2的幂次,这样的话2的幂-1都是11111结尾的(16->10000,15->01111),当容量一定是2^n时,tab[i = (2^n - 1) & hash] == tab [i=(hash%2^n)]

相关文章:

  • JDK1.8源码 resize()解析
  • HashMap中的迭代器
  • Hashtable中的get(key)方法,为什么进行hash 0x7FFFFFFF
  • Hashtable中的rehash()方法
  • mysql查询一个时间段的数据
  • Linux中的shell是什么
  • JUC笔记
  • 共享模型之管程
  • 共享模型之内存
  • 共享模型之无锁
  • 全面解析ThreadLocal
  • BIO-NIO-AIO笔记
  • docker 运行出错 Error response from daemon: error creating overlay mount to /var/lib/docker/overlay2/007
  • JAVA多态
  • 状态压缩DP--------蒙德里安的梦想
  • 10个最佳ES6特性 ES7与ES8的特性
  • Angular Elements 及其运作原理
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • FastReport在线报表设计器工作原理
  • js ES6 求数组的交集,并集,还有差集
  • oldjun 检测网站的经验
  • PhantomJS 安装
  • React-redux的原理以及使用
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 来,膜拜下android roadmap,强大的执行力
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 探索 JS 中的模块化
  • 通过npm或yarn自动生成vue组件
  • ​queue --- 一个同步的队列类​
  • #14vue3生成表单并跳转到外部地址的方式
  • #NOIP 2014# day.2 T2 寻找道路
  • (c语言)strcpy函数用法
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (转)大道至简,职场上做人做事做管理
  • **PyTorch月学习计划 - 第一周;第6-7天: 自动梯度(Autograd)**
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • ::前边啥也没有
  • [ C++ ] STL---string类的使用指南
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林
  • [Android]Tool-Systrace
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作
  • [BUG] Authentication Error
  • [C#] 如何调用Python脚本程序
  • [GDOUCTF 2023]<ez_ze> SSTI 过滤数字 大括号{等
  • [javaee基础] 常见的javaweb笔试选择题含答案
  • [LeeCode]-Divide Two Integers 不用乘除的除法运算
  • [LeetCode] 197. 上升的温度
  • [LeetCode] Sort List
  • [LeetCode]—Permutations 求全排列
  • [MySQL FAQ]系列 -- 账号密码包含反斜线时怎么办