java jdk1.7版本的HashMap原理解析
2016-08-26 17:50
621 查看
HashMap是一个key-value集合,每一个key对应一个值,key不可以重复,对相同的key进行设值将会把原来的值进行覆盖。HashMap的底层实现原理是利用一个数组和多个单向链表实现的一个数据集合,数组的每个数据项就是一个单向链表(实际上是通过一个个Entry实例连接起来,Entry有一个next变量指向下一个元素),数组里的每个存放数据的位置我们称为桶。当要put一个键值对进去集合时,首先将会对键值对的键的hashcode进行一定的运算,运算出来是一个int类型的数据,HashMap将会根据这个int类型的数据对应到数组的一个下标,然后利用新增的键值对创建一个Entry的实例,最后把这个Entry实例加到这个下标对应的单向链表中,后加入的Entry实例将会在单向链表的前面。首先我们直观的看下HashMap数据存储结构:
Entry数据结构:
HashMap的特点:
(1)、HashMap实现了Map接口,其具有Map所有的操作;
(2)、HashMap的key和value都允许设置null值;
(3)、HashMap存放的数据是乱序的,迭代的时候不会根据存入的顺序进行迭代,也不会根据key进行排序迭代;
(4)、HashMap不是线程安全的,如果要创建一个线程安全的HashMap,可以这样创建:
Map m = Collections.synchronizedMap(new HashMap(…));
(5)、HashMap的迭代器 iterator 方法返回的迭代器是快速失败 的。所谓快速失败,意思就是如果在迭代器已经创建了的情况下,任何时刻对HashMap结构的修改,迭代器将会抛出一个ConcurrentModificationException异常。其原理是HashMap中维护了一个变量modCount,代表修改的次数,当创建迭代器时,会把这个变量保存到迭代器实例的expectedModCount变量中,在迭代的过程中会把迭代器保存的expectedModCount与modCount对比,如果发现不相等就抛出异常。如下面代码中迭代器已经生成,但是还往HashMap添加数据,那么此后的迭代过程是会抛出ConcurrentModificationException异常:
HashMap的变量说明:
(1)、table:HashMap里利用这个变量保存了整个HashMap的数据,其是一个Entry的数组:
(2)、size:HashMap中实际保存数据的数量,每put一个键值对增加1,每remove一个键值对减1。
HashMap方法实现细节:
put(K key, V value)方法,执行流程:
(1)、首先检测table变量是否已经初始化完成,如果没有初始化,则根据参数初始化table变量,实际上完成的事情是创建一个具有长度的数组;
(2)、检测传入的key是否为null,如果为null,则调用putForNullKey方法把键值对放到table数组下标为0的位置,否则进行下一步;
(3)、根据key的hashCode运算出一个int类型的数据,根据这个int类型数据调用indexFor方法找到新增的键值对应该放到table的那个下标的桶下;
(4)、根据找到的下标寻找是否该key已经在HashMap中,如果在,则更新旧值,并把旧值返回,否则进行下一步;
(5)、调用addEntry方法,判断HashMap是否需要扩容,如果需要,则把table扩充为原来的两倍。否则创建一个Entry实例,加入到对应下标的链表中。
代码截图:
get(Object key)方法,执行流程:
(1)、首先判断传入的key是否为null,如果为null,则调用getForNullKey获取key为null的值,否则进行下一步;
(2)、调用getEntry方法,根据key获取到对应的实例,获取逻辑跟put方法的逻辑类似,即首先根据key获取到table数组的下标,然后根据key对比获取到对应的Entry实例;
(3)、根据返回的实例返回实例的值。
代码截图:
HashMap与Hashtable的区别:
HashMap与Hashtable的底层实现原理一样,数据结构也一样,都是利用数组和单向链表实现。主要的区别有以下几点:
(1)、Hashtable是线程安全的,其方法都加了synchronized修饰;而HashMap不是线程安全的;
(2)、Hashtable的key和value都不允许为null,而HashMap允许;
(3)、hashMap去掉了HashTable 的contains方法,但是加上了containsValue和containsKey方法。
Entry数据结构:
HashMap的特点:
(1)、HashMap实现了Map接口,其具有Map所有的操作;
(2)、HashMap的key和value都允许设置null值;
(3)、HashMap存放的数据是乱序的,迭代的时候不会根据存入的顺序进行迭代,也不会根据key进行排序迭代;
(4)、HashMap不是线程安全的,如果要创建一个线程安全的HashMap,可以这样创建:
Map m = Collections.synchronizedMap(new HashMap(…));
(5)、HashMap的迭代器 iterator 方法返回的迭代器是快速失败 的。所谓快速失败,意思就是如果在迭代器已经创建了的情况下,任何时刻对HashMap结构的修改,迭代器将会抛出一个ConcurrentModificationException异常。其原理是HashMap中维护了一个变量modCount,代表修改的次数,当创建迭代器时,会把这个变量保存到迭代器实例的expectedModCount变量中,在迭代的过程中会把迭代器保存的expectedModCount与modCount对比,如果发现不相等就抛出异常。如下面代码中迭代器已经生成,但是还往HashMap添加数据,那么此后的迭代过程是会抛出ConcurrentModificationException异常:
HashMap的变量说明:
(1)、table:HashMap里利用这个变量保存了整个HashMap的数据,其是一个Entry的数组:
(2)、size:HashMap中实际保存数据的数量,每put一个键值对增加1,每remove一个键值对减1。
HashMap方法实现细节:
put(K key, V value)方法,执行流程:
(1)、首先检测table变量是否已经初始化完成,如果没有初始化,则根据参数初始化table变量,实际上完成的事情是创建一个具有长度的数组;
(2)、检测传入的key是否为null,如果为null,则调用putForNullKey方法把键值对放到table数组下标为0的位置,否则进行下一步;
(3)、根据key的hashCode运算出一个int类型的数据,根据这个int类型数据调用indexFor方法找到新增的键值对应该放到table的那个下标的桶下;
(4)、根据找到的下标寻找是否该key已经在HashMap中,如果在,则更新旧值,并把旧值返回,否则进行下一步;
(5)、调用addEntry方法,判断HashMap是否需要扩容,如果需要,则把table扩充为原来的两倍。否则创建一个Entry实例,加入到对应下标的链表中。
代码截图:
get(Object key)方法,执行流程:
(1)、首先判断传入的key是否为null,如果为null,则调用getForNullKey获取key为null的值,否则进行下一步;
(2)、调用getEntry方法,根据key获取到对应的实例,获取逻辑跟put方法的逻辑类似,即首先根据key获取到table数组的下标,然后根据key对比获取到对应的Entry实例;
(3)、根据返回的实例返回实例的值。
代码截图:
HashMap与Hashtable的区别:
HashMap与Hashtable的底层实现原理一样,数据结构也一样,都是利用数组和单向链表实现。主要的区别有以下几点:
(1)、Hashtable是线程安全的,其方法都加了synchronized修饰;而HashMap不是线程安全的;
(2)、Hashtable的key和value都不允许为null,而HashMap允许;
(3)、hashMap去掉了HashTable 的contains方法,但是加上了containsValue和containsKey方法。
相关文章推荐
- java jdk1.7版本的ArrayList原理解析
- java jdk1.7版本的LinkedList底层原理解析
- 【Java并发】- ConcurrentHashMap原理解析(Segment版本)(转)
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
- 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)
- JDK 1.7 HashMap原理及源码解析
- 【Java并发】- ConcurrentHashMap原理解析(JDK1.8)
- Java内存区域划分、内存分配原理(基于jdk1.7 源自 《深入理解java虚拟机》)
- 【图解JDK源码】HashMap的容量大小增长原理(JDK1.6/1.7/1.8)
- Java中HashMap底层实现原理(JDK1.8)源码分析
- Java--String源码解析(JDK1.7)
- myeclipse里工程的jdk使用的1.7版本,其中java compiler最高只能选到1.6的问题(在maven工程中出现的问题) -- 记录
- Java集合框架--HashMap源码解析(JDK1.7)
- 修改maven项目jdk版本,并解决Dynamic Web Module 3.1 requires Java 1.7 or newer错误
- Java-Concurrent框架--ConcurrentHashMap源码解析(JDK1.7)
- 将jdk版本:jdk1.8更换为jdk1.7之后输入java -version还是出现1.8的版本号
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析
- 【Java】Linux下安装配置Oracle JDK 1.7版本
- Eclipse打war包方法以及Eclipse移植项目时JDK版本不匹配Project facet Java version 1.7 is not supported
- Java 各版本API文档 JDK1.5 JDK1.6 JDK1.7 没事看看