HashMap剖析及原理实现

HashMap是Java中使用最多的用于映射的(Key - value)处理的数据类型。

  • JDK1.7:HashMap的底层实现是  数组 + 链表
  • JDK1.8:HashMap的底层引入了红黑树  数组 + 链表 + 红黑树

HashMap添加元素:

在HashMap中添加元素时,会通过hash值和数组的长度来计算得出一个计算下标值,用它来准确定位该元素应该put的位置,通常,我们为了使元素分布均匀会使用取模运算,用一个值去模数组总长度。(但此时会有一个大问题就是会出现hash冲突。)

拓展介绍:

Java为数据结构中的映射定义了一个接口java.util.Map,这个接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap,类继承关系如下图所示:

HashMap剖析及原理实现

  • HashMap:

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。根据键的hashcode值存储数据,大多数情况下可以直接定位到它的值,因此访问速度较快,但是由于hashcode的值是随机的,所以遍历顺序也是不确定的。HashMap最多只允许一条记录的键为null。hashmap的线程是不安全的(同一时刻可以有多个线程同时对hashmap进行操作。hashmap会进行resize操作,在resize操作的时候会造成线程不安全。1.put的时候导致多线程数据不一样。2.hashmap的get操作可能因为resize而引起死循环(cpu100%))。如果需要满足线程安全,可以考虑使用Collections的SynchronizedMap方法使HashMap具有线程安全,或者使用ConcurrentHashMap。

 

  • HashTable:

也叫散列表。是根据关键码值(Key - value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。与hashmap不同,HashTable继承Dictionary类,但很多功能与hashmap类似,而且重要的是hashtable是线程安全的,HashTable使用Synchronized来实现线程安全,全局只有一把锁。在同一事件上,只能有一个线程对hashtable进行操作,当线程竞争激烈的时候,HashTable效率是比较低的。相比较于ConcurrentHashMap,hashtable的并发性并不好,因为在ConcurrentHashMap中引入使用了分段锁,HashTable一般很少使用,因为可以用HashMap和ConcurrentHashMap在需要使用的场景中替换掉HashTable。相当于是hashtable对另外两个都有涉及,但都不精进,而另外两个都是在自己领域上非常精进的。

 

  • LinkedHashMap:

LinkedHashMap是HashMap下的一个子类,保存记录的插入顺序,在使用Iterator遍历LinkedHashMap时,先得到的记录时先插入的,也可以在构造时传递参数,按照访问次数来进行排序。与HashMap的不同点就是,它将键-值对以插入顺序进行排列,即遍历的时候会按照插入的顺序进行访问元素。

 

  • TreeMap:

TreeMap实现SortedMap接口,能够把它保存的记录,根据键排序,默认是按键值的升序排序,也可以是指定的排序比较,在使用Iterator遍历TreeMap时,得到的记录时经过排序后的,如果使用排序的映射,推荐使用treeMap.

 

上面四种Map类型的类,其中的key值必须是不可变的,不可变对象是该对象创建后它的hash值不会被改变,如果对象hash值发生了改变,那么Map对象就不能成功定位到映射位置。

 

HashMap & TreeMap:

  • 都实现了Map接口,HashMap对键进行散列,TreeMap用键的整体顺序对元素进行排序,并将其组织成搜索树
  • 散列或比较函数均只作用于键。与键关联的值不能进行散列或者比较。
  • HashMap比TreeMap搜素效率稍微快一些,所以在不需要按照排列顺序访问键时,推荐使用HashMap.

 

红黑树:

前面讲到,当链表过长时,查询效率就会变低,链表查询的时间复杂度是O(n),而数组是O(1),所以在这种情况下就引入了第三种数据结构,“红黑树”,当链表的长度 >= 8时链表转化为红黑树,红黑树(Red Black Tree) 是一种自平衡二叉查找树,查询的时间复杂度为O(logn),(扩展一下,排序中,跟树有关的时间复杂度都是O(logn),因为n个节点的树对应的深度是logn,例如归并排序,快速排序,堆排序都是O(nlogn),)远远比链表的查询效率高。

 

上一篇:TreeMap解析


下一篇:TreeMap底层实现和原理-红黑树