HashMap 实现了Map 接口,其底层以一个线性数组保存哈希表,所以它既有数组查询的高效,也有哈希存取的方便。

HashMap提供了默认构造器,和有参构造器,在有参构造器中,提供了两个参数,可以对集合长度和加载因子自定义。如果不传,默认长度为16,加载因子为0.75,所以实际初始临界长度为16*0.75 = 12。

HashMap 定义了一个内部类Entry<K,V>,从外形上可以看出,HashMap的值实际上就是保存在这个自定义的类上。然后定义了一个transient 的数组,数组类型为Entry。

HashMap在通过put(key,value)设置的时候,首先会拿到key,拿到它的哈希值,key.hashcode(),通过它的一个算法得到新的哈希值

然后通过算法得到value在entry数组中的下标或者叫索引

以下是它的put方法

通过观察可以发现,在存值的时候,首先会对数组进行循环判断,判断它们的KEY和将要存储的KEY的哈希值进行比较,如果相同,则会覆盖掉value,然后把旧的value返回.有意思的是,两个key的hash相同必须同时满足两个条件,即“==”和“equals”同时为true,如果不同时满足这两个条件,但它们KEY的哈希又确实相等,确实有这种情况,即“==”返回true,而“equals”返回false,那么它实际上将不会覆盖,而是在相应的数组节点上,通过entry的next属性形成一个entry链,后进来的排在最前面.

那么这会形成两个问题:1是有的数组节点上形成了一个较长的entry链,而另外的节点上还没有一个值。这大约可以通过增大加载因子来调节;2是数组节点上entry链过长,它会影响查找效率。在加载因子不变的情况下,只有增加长度了。HashMap靠resize()来重设长度,那么,HashMap在什么去增加长度呢?

通过搜索可以发现,在每次put的时候,都会去调用resize()

通过resize()方法可以发现,如果数组超过临界长度,长度会默认增长为当前两倍.那么这就会出现一个新的问题,简单起见,假设原先存储数据的key.hashcode()=5,%12=7,那么这条数据就存在数组下标为7的地方,如果数组长度不够,默认增加一倍就为了24,这时候%24=19,在读取的时候它不是就会跑到数组下标为19的地方去找?考虑到这一点,HashMap会调用一个方法叫做transfer()将原数组取key重新计算在新的数组里的下标。

这个方法会将原先的每条数据遍历,重新计算,然后转移到新的数组。这将会是非常影响效率的操作。

前面讲到数组entry[]table 修饰符为transient,因此,它是不直接包含在序列化里的。HashMap通过迭代器来遍历,它的内部有一个泛型的抽象类HashIterator<E>,同时ValueIterator,KeyIterator,去实现了这个类,在HashMap迭代的时候,通过两个属性来控制方法的同步。一个是modCount,在HashMap的每一个方法,包括put,remove里面,都会看到这个属性,每一次操作它自增。它表示对这个集合更新的次数。假设在迭代之前,modCount为18,然后把值赋给另一属性expectedCount(预期值),如果在迭代操作未完成之前,这个命令被另一个线程进行了一次操作,那么这时modcount=19,它在指向nextEtry即下一个元素之前 ,会去比较两个值,如果不相等,就会抛出异常ConcurrentModificationException().

学习笔记--HashMap浅析的更多相关文章

  1. JDK源码学习笔记——HashMap

    Java集合的学习先理清数据结构: 一.属性 //哈希桶,存放链表. 长度是2的N次方,或者初始化时为0. transient Node<K,V>[] table; //最大容量 2的30 ...

  2. Java泛型学习笔记 - (七)浅析泛型中通配符的使用

    一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List< ...

  3. 【Mysql学习笔记】浅析mysql的binlog

    最近读一份关于“数据库事务故障恢复"的技术资料,发现对mysql的binlog的认识不够清楚,查阅mysql reference manual有所收获,作为笔记,记录于此. 1. What' ...

  4. Java学习笔记--HashMap中使用object做key的问题【转】

    在HashMap中,如果需要使用多个属性组合作为key,可以将这几个属性组合成一个对象作为key.但是存在的问题是,要做get时,往往没办法保存当初put操作时的key object的referenc ...

  5. 【学习笔记】浅析后缀自动机(SAM)及基础应用

    解决子串相关问题的强大工具 我们知道一个长度为 \(n\) 的字符串中所有的子串数目为 \(O(n^2)\) 个,这很大程度上限制了我们对某些子串相关问题的研究.所以有没有解决方案,使得我们可以在可承 ...

  6. 【学习笔记】浅析Promise函数

    一.Promise是什么? 在JavaScript中,所有的代码都是单线程执行,所以javaScript的所有网络操作(“GET”/"POST"/"PUT"/& ...

  7. 【Web学习笔记】浅析CGI概念及用法

    1. CGI是什么         CGI是Common Gateway Interface的简写,它提供了一种标准方法使得位于WebServer后端的web应用可以根据client的请求动态生成网页 ...

  8. 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值

    常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...

  9. JDK源码学习笔记——LinkedHashMap

    HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...

随机推荐

  1. Idea基本设置

    1.idea 如何更改比编辑器文本字体和大小 换上了intellij idea之后,第一件事就是想要改变下文字字体,因为在我这个27寸的2k分辨率的屏幕上,文字显然太小了. intellij idea ...

  2. Objective-C数据类型、数据类型转换

    数据类型 1.Objective-C数据类型可以分为:基本数据类型.对象数据类型和id类型. 2.基本数据类型有:int.float.double和char类型. 3.对象类型就是类或协议所声明的指针 ...

  3. jQuery身份证验证插件

    jQuery身份证验证插件 /*! * jQuery isIDCard Plugin v1.0.0 * http://www.cnblogs.com/cssfirefly/p/5629561.html ...

  4. spark概论,补充

    基本概念 RDD spark最大的亮点是提出RDD(Resilient Distributed Dataset)的概念,也就是可伸缩的分布式数据集合,本身只读,可恢复.spark本身不做物理储存,通过 ...

  5. Windows Server 2003开机自动启动MySQL服务设置方法

    Windows Server 2003开机自动启动MySQL服务设置方法 发布时间:2014-12-19 更新时间:2014-12-24 来源:网络 作者:eaglezhong 关键词: 2003 e ...

  6. 每天进步一点--c#基础巩固,事件、委托

    要想技术有所提高,就是把有些问题真正的弄懂弄明白,我从事C#开发两年了,一直对事件委托等概念一知半解,有时候博客园上看看别的大牛的文章,看看懂了就过去了,时间长了又忘了,真正理解还是要自己动手弄些例子 ...

  7. EF经验分享_jimmyzzc

    刚刚接触EF,总结了一些在实际工作中的心德经验,与大家分享一下. 一.Excression表达式树 表达式目录树在LINQ中用于表示分配给类型为Expression<TDelegate>的 ...

  8. Android Studio添加aar包依赖

    1.将aar包考入需要依赖的模块的libs目录下 2.在需要依赖的模块的build.gradle中添加如下内容: dependencies { compile(name:'aar包名不带扩展名', e ...

  9. char与 int 类型转化问题汇总

    1.char变为int时高位符号扩展问题 int main() { char a = 0x9a; int util; util = (int)a; if(util > 0) printf(&qu ...

  10. [转]从普通DLL中导出C++类 – dllexport和dllimport的使用方法(中英对照、附注解)

      这几天写几个小程序练手,在准备将一个类导出时,发现还真不知道如果不用MFC的扩展DLL,是怎么导出的.但我知道dllexport可以导出函数和变量,而且MFC扩展DLL就算是使用了MFC的功能,但 ...