本文主要是从学习的角度看HashMap源码

HashMap的数据结构

  • HashMap是一个数组+链表的结构(链表散列),每个节点在HashMap中以一个Node存在;

HashMap的初始化

    public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
// 这里的MAXIMUM_CAPACITY=1 << 30(问题一: 为什么是30?)
if (initialCapacity > MAXIMUM_CAPACITY)
// 如果传入初始值大于1<<30 则默认值为最大;
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
// 这里是根据传入的初始值算得 大于输入参数且最近的2的整数次幂的数
this.threshold = tableSizeFor(initialCapacity);
}
  • HashMap中初始化方法如上。

    • initialCapacity参数为初始化大小的值,默认为16,问题二:这里为什么为16?;
    • loadFactor参数我理解为扩容权重比,默认值为0.75,问题三:这里为什么是0.75?,就是当HashMap的容量达到HashMap的数组长度*loadFactor时就会进行扩容。也就是HashMap中的 resize 方法
  • 初始化方法代码不多,此处为了效率运用了很多的位运算;

    首先: 为什么HashMap的容量永远是2的整数倍?
    • 首先我们可以看源码知道HashMap中元素的位置计算是 hash & (n- 1),为啥要这么算我也不知道,反正这样的算法下 如果hashmap的长度刚好是2的倍数那么元素的分布相对来说是比较均匀的。减少元素碰撞的几率; 具体详细的可以看下这篇博文
    • 所以这也解释了问题二的初始值为16即2的四次方;至于为啥一定是16,我也不知道,可能我比较杠精;
    • 更新(12-11 ): 此处为什么是16在关于这个默认容量的选择,JDK并没有给出官方解释,我也没有在网上找到关于这个任何有价值的资料。(如果哪位有相关的权威资料或者想法,可以留言交流)
    • 更新(12-23):详见问题二
问题一:MAXIMUM_CAPACITY = 1 << 30
  • 首先这个值符合上面的原则,即大小为2的整数倍;而1<<30这个值我们可以尝试发现:
       System.out.println(1<<30); // 1073741824
    System.out.println(1<<31); // -2147483648
    System.out.println(1<<32); // 1
  • 因为int类型是32位整型,1左移31位的为 16进制的0x80000000代表的是-2147483648, 所以最大值只能为1>>30;至于为什么初始值不用Integer.MAX_VALUE,其实在resize方法中有下面这段代码:
            if (oldCap >= MAXIMUM_CAPACITY) {
    //若数组长度大于1>>30,这里则扩容Integer.MAX_VALUE;
    threshold = Integer.MAX_VALUE;
    return oldTab;
    }
问题二:initialCapacity初始值为16

因为在使用是2的幂的数字的时候,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。

只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。

这是为了实现均匀分布。

问题三: loadFactor默认值0.75

JDK 1.7中:

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.

  • 翻译过来就是:

    作为一般规则,默认负载因子(0.75)在时间和空间成本上提供了很好的折衷。较高的值会降低空间开销,但提高查找成本(体现在大多数的HashMap类的操作,包括get和put)。设置初始大小时,应该考虑预计的entry数在map及其负载系数,并且尽量减少rehash操作的次数。如果初始容量大于最大条目数除以负载因子,rehash操作将不会发生。

  • 理想状态下,在随机哈希值的情况,对于loadfactor = 0.75 ,虽然由于粒度调整会产生较大的方差,桶中的Node的分布频率服从参数为0.5的泊松分布。

接下来我们会具体看下HashMap的resize方法

博文推荐:https://www.hollischuang.com/archives/4320 (掘金看见的,写的很好)

HashMap源码(一)的更多相关文章

  1. HashMap 源码解析

    HashMap简介: HashMap在日常的开发中应用的非常之广泛,它是基于Hash表,实现了Map接口,以键值对(key-value)形式进行数据存储,HashMap在数据结构上使用的是数组+链表. ...

  2. HashMap源码分析

    最近一直特别忙,好不容易闲下来了.准备把HashMap的知识总结一下,很久以前看过HashMap源码.一直想把集合类的知识都总结一下,加深自己的基础.我觉的java的集合类特别重要,能够深刻理解和应用 ...

  3. JAVA源码分析-HashMap源码分析(一)

    一直以来,HashMap就是Java面试过程中的常客,不管是刚毕业的,还是工作了好多年的同学,在Java面试过程中,经常会被问到HashMap相关的一些问题,而且每次面试都被问到一些自己平时没有注意的 ...

  4. Java集合---HashMap源码剖析

    一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调整大小 5.数据读取           ...

  5. 【转】Java HashMap 源码解析(好文章)

    ­ .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...

  6. 【JAVA集合】HashMap源码分析(转载)

    原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...

  7. HashMap源码解读(转)

    http://www.360doc.com/content/10/1214/22/573136_78188909.shtml 最近朋友推荐的一个很好的工作,又是面了2轮没通过,已经是好几次朋友内推没过 ...

  8. HashMap源码剖析

    HashMap源码剖析 无论是在平时的练习还是项目当中,HashMap用的是非常的广,真可谓无处不在.平时用的时候只知道HashMap是用来存储键值对的,却不知道它的底层是如何实现的. 一.HashM ...

  9. Java中HashMap源码分析

    一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...

  10. 转:【Java集合源码剖析】HashMap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...

随机推荐

  1. Foxmail for windows 客户端设置和 IMAP、POP3/SMTP 的设置

    Foxmail支持微信扫码.手机验证码.账号密码三种方式新建腾讯企业邮箱. 注意:目前仅foxmail 7.2.11版本支持微信扫码和手机验证码新建腾讯企业邮箱,可以foxmail官网https:// ...

  2. JS隐藏显示图片

    <!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8 ...

  3. 小白的linux笔记4:几种共享文件方式的速度测试——SFTP(SSH)/FTP/SMB

    测试一下各个协议的速度,用一个7205M的centos的ISO文件上传下载.5Gwifi连接时,本地SSD(Y7000)对服务器的HDD: smb download 23M/s(资源管理器) smb ...

  4. ext4文件系统启动自检的必要性

    最近我们发现多个用户设备掉电后重启,系统不工作. 研究这些返修设备,发现这些设备的表象是网络连接失败,DNS resolve不了.进一步发现/etc/resolv.conf为空,所以应用程序没法进行D ...

  5. 金融计算的开源库——QuantLib 学习入门

    本文在Creative Commons协议下发布. 简介 瞬息万变的金融市场开发出了太多的金融产品,产生了太多的计算问题,这对于 Fintech 来讲:无论是计算能力上的,还是软件设计上的是一个巨大的 ...

  6. pytest文档32-allure描述用例详细讲解

    前言 pytest+allure是最完美的结合了,关于allure的使用,本篇做一个总结. allure报告可以很多详细的信息描述测试用例,包括epic.feature.story.title.iss ...

  7. [PKUWC2018]Minimax [dp,线段树合并]

    好妙的一个题- 我们设 \(f_{i,j}\) 为 \(i\) 节点出现 \(j\) 的概率 设 \(l = ch[i][0] , r = ch[i][1]\) 即左儿子右儿子 设 \(m\) 为叶子 ...

  8. L001.PyQt

    초보자를 위한 Python GUI 프로그래밍 - PyQt5 https://wikidocs.net/book/2944 https://freeprog.tistory.com/330?cat ...

  9. Linux 进程调度笔记(一)

    主要讨论的是单核 CPU 的情况下,进行调度的一些算法和思路.讨论都是基于单核 CPU 的条件下进行. 在内存中,无论对于用户而言有多少个进程,但在 CPU 运行的时候,总是只有只执行一个进程.进程调 ...

  10. 【database】oracle集合 - Associative Arrays、Varrays、Nested Tables

    前言 参考oracle官方文档:PL/SQL Language Reference 11g Release 2  -  5 PL/SQL Collections and Records 可以去看下文档 ...