jdk1.7 和 1.8 大致相同但还是有区别,主要是数据结构的区别,1.7 为数组+链表;1.8 为数组+链表+红黑树

关键知识点

  • 加载因子:装填因子,目的是何时对 map 进行扩容,默认是 0.75 即容量达到 75% 时对 map 扩容,原数组扩大为两倍长度
  • 扩容阈值,根据数组长度和加载因子相乘得到的值,达到这个值就会扩容
  • hash 算法:也叫hash函数,hash运算,指的是把 key 换算成数组的下标的算法(hashCode+数组长度+一系列右移和异或运算)
  • hash 冲突:不同的 key 经过 hash 运算后得到了相同的数组下标(这时数组元素不止一个,解决的方式很多,java 采用 链式寻址法 也就是链表来解决)
  • 数组长度默认是 16,且长度只会是 2 的指数个数(初始化指定的长度实际会是当前值最接近2的指数的值,比如指定为3,实际会是8)
  • new HashMap() 时不会初始化数组,在 put 的时候才会初始化,具体是 put 时判断数组是否为空,如果为空再创建长度为 16 的数组
  • 数组的元素是链表,这个说法不是特别准确,只是说可以这样理解,准确的说法是数组的元素是链表的头节点

jdk 1.7 put 过程

  • 判断数组(table)是否为空,如果为空就先创建数组(put 才初始化数组,扩容阈值等也是 put 时确定,懒加载思维)

    • 如果不指定长度,默认就是16
    • 如果指定长度,并不是创建指定长度的数组,而是根据指定的长度得到最接近 2 的指数值,把这个值作为数组长度来初始化
  • hash 运算得到数组下标 i
    • 先得到 hashCode,hashCode 远远不够,还需要别的运算才能满足当前数组的下标范围
    • 把 hashCode 多次右移和异或运算得到一个值(hash 值)
    • 把 hash 值和数组长度-1做与运算(i = h & length-1),因为要保证这里的与运算能正确得到符合数组的下标,所以数组的长度必须是 2 的指数
  • 把元素放入数组下标i的位置,分两种情况:当前位置有值和没有值
    • 如果有值,table[i] 就是个链表,遍历这个链表,也会有两种情况,key 重复和不重复(使用 equals 比较),如果 key 重复就覆盖,返回原来的值,流程结束
    • 如果没有值或者 key 不重复,继续往下走,执行新增逻辑,addEntry 方法
  • 新增元素 addEntry 方法逻辑(如果 table[i] 为空,table[i] 就放当前 entry,如果不为空那就是个链表,头插法维护链表)
    • 如果 size + 1 大于扩容阈值(长度*负载因子)会先进行扩容,table 长度变为原来的 2 倍,扩容方法是resize(2 * teble.length)
    • 如果 size + 1 不大于扩容阈值,就把 key-value 构建成一个节点(Entry 对象)采用头插法维护 table[i] 的链表
    • size++,返回 null,流程结束

jdk1.7 扩容

创建一个新的 table, 长度变为原来的 table 的两倍,首先把原来 table 的元素先全部拷贝到新的 table 中,拷贝的的过程中不是简单复制数组,而是重新 根据新的 table 长度进行哈希运算,把原来的元素放进新的 table 中,这样有个显著的特点,因为 table 变成了,所以 hash 运算得到的下标和原来的下标不一样,这样就会更少的发生 hash 冲突,从而把链表的长度变短

jdk1.7 get

只要明白 put 就应该能明白 get,因为 put 会先找一遍,如果没有再新增 entry。get 大概逻辑:

  • 根据 key 得到 hashCode
  • 再经过 hash 函数(多次右移+异或)得到 hash
  • 根据 hash 和 数组长度-1(数组下标)进行与运算得到数组下标
  • 再用 eauals 比较链表的 key,如果相等就获取返回

最新文章

  1. maven编译报错 -source 1.5 中不支持 lambda 表达式
  2. Java 多张图片合成一张 drawImage
  3. inotifywait命令
  4. ListView上拉加载,下拉刷新 PullToRefresh的使用
  5. Logdump使用指引
  6. github神器--Atom编辑器初体验
  7. JS图片延迟加载分析及简单的demo
  8. CNV
  9. Wamp安装使用+Git for Windows
  10. 实现CCLayer只显示一个矩形可见区域
  11. Windows Server 2008找回密码
  12. HDU 4432 Sum of divisors (进制模拟)
  13. UVA10304---(区间DP)
  14. Kindeditor JS 富文本编辑器图片上传指定路径
  15. js-ES6学习笔记-Set结构和Map结构
  16. 设计模式NO.2
  17. 用asp.net core 把用户访问记录优化到极致
  18. (转载)Java Map中的Value值如何做到可以为任意类型的值
  19. 解决依赖冲突:maven-enforcer-plugin插件
  20. Sql语句出错:Unknown column 'CLAMP' in 'where clause'

热门文章

  1. angular在服务中调用组件的某个方法,并传参给组件,(反向调用),变量改变后,强制更新视图
  2. 「HNOI2019」校园旅行
  3. 数据结构-详解优先队列的二叉堆(最大堆)原理、实现和应用-C和Python
  4. 《深入理解Java虚拟机》第三章读书笔记(二)——HotSpot垃圾回收算法实现(OopMap,安全点安全区域,卡表,写屏障,三色标记算法)
  5. 重学SpringBoot. step4 Redis的应用
  6. Spring(IOC实际开发使用、底层原理)
  7. 部署Kubernetes v1.22.10高可用集群
  8. 深度学习-LSTM
  9. Vmware15 + Ubuntu18.0.4 安装教程(史上最详细记录)【多图预警】
  10. Java对象布局