hashmap返回最大值_几根头发飘落在阅读HashMap的屏幕前

前言

HashMap是一个不管在工作中还是面试中,都经常会碰到地一种集合,对其进行学习,不管对其他源码的学习还是更合理的使用HashMap上都有很大的帮助。

本篇主体以HashMap最常用的put,remove而展开的源码解析。

灵魂一问

了解过HashMap的人应该都知道HashMap的默认容量是2 n ,扩容也是按两倍扩容。 这里大家肯定想说:

9e8861dae0ba583aac3fa28e979e9234.png

为什么HashMap容量都是2的n次幂呢?

HashMap是利用hash值来计算应该存放在数组中的位置。如果hash值大于当前容量呢,该怎么计算,一般都会想到用求余的方法:index = hash % size,这样能分散得出在当前容量的table中的位置。不过这样真的好吗?

求余运算在编译后是这样的: a % b 旧相当与 a - (a / b) * b 的运算。是多步运算。

而 & 运算,编译后就是一条CPU指令,效率要比求余快得多。而当b是2 n 时,a % b 的结果等同于 (b-1) & a 。

d9d81bb30cd69ce652fd3ed3e0c1ab08.png

而HashMap就是通过这样,高效的算出一个桶的index在哪里。

成员变量

话不多说切入正题。

这里大致描述每个变量的作用,后面源码分析中,会进一步看到变量如何使用。

  • 默认容量 2 4
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;复制代码
  • 最大容量 2 30
static final int MAXIMUM_CAPACITY = 1 << 30;复制代码

由上面两个变量以即HashMap的扩容为2倍的机制,不禁会有一个疑问。

为什么HashMap容量都是2的n次幂呢?

大家都知道HashMap是利用hash值来计算应该存放在数组中的位置。如果hash值大于当前容量呢,该怎么计算,

  • 默认加载因子(笔者比较喜欢称作扩容系数)
static final float DEFAULT_LOAD_FACTOR = 0.75f;复制代码
  • 树化阈值(链表长度到达这个值就会转换为树结构)
static final int TREEIFY_THRESHOLD = 8;复制代码
  • 解除树形阈值(树的节点树小于这个长度就会退化为链表结构)
static final int UNTREEIFY_THRESHOLD = 6;复制代码
  • 最小树化容量(当Node数组容量小于这个值时不会树化,只会扩容)
static final int MIN_TREEIFY_CAPACITY = 64;复制代码
  • 桶数组
transient Node[] table;复制代码
  • 桶集合(用来提供hashMap的集合操作,本身不存储元素)
transient Set> entrySet;复制代码
  • 容量大小
transient int size;复制代码
  • 修改的次数
transient int modCount;复制代码

hashMap在迭代的时候,会把modCount传入,作为期望值(类似于乐观锁)如果迭代的时候其他线程进行了增删改操作,modCount就会改变,改变后继续迭代会抛出异常ConcurrentModificationException。

  • 节点数组(大部分都把它叫桶数组)
transient Node[] table;复制代码
  • 扩容阈值
int threshold;复制代码

到达这个值,HashMap就会执行扩容

桶的结构

本篇源码都是JDK1.8版本的,在1.8之后,HashMap的桶内结构分为两种,一种是链表,还有一种树结构。

链表

static class Node implements Map.Entry {        final int hash; //hash值        final K key;  //键        V value; //值        Node next; //下一个节点                ...    }复制代码

static final class TreeNode extends LinkedHashMap.Entry {        TreeNode parent;  // 父节点        TreeNode left;  //左子节点        TreeNode right; //右子节点        TreeNode prev;    //前节点        boolean red; //是否为红节点    }复制代码

这里继承了LinkHashMap的Entry,而LinkHashMap的Entry又继承了HashMap的Node。所以这里的树节点,不仅是红黑树结构,还包含着一个双向链表。类似下图这种关系,除了树的根节点是链表的首节点之外,链表顺序与树节点顺序没有什么关系(后面源码之中也会验证这一点)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值