java基础--结合面试谈hashMap

来源:互联网 发布:宝鸡加工中心编程招聘 编辑:程序博客网 时间:2024/06/15 02:15

       说到集合,我们都会想到数组、hashmap,加上最近面试被问到的频度,特意把hashmap的一些总结分享给大家,希望能给大家带来帮助:

 1.hashmap的数据结构

       提到hashmap,想必大家都知道,它的存储结构是数组 + 链表,在java编程语言中,两种最基本的结构(数组 + 指针)可以组成任意的数据结构,而hashmap也不例外:hashmap是数组和链表的结合体(在数据结构中,被称为“链表散列”):


        当我们初始化一个hashmap时,其实就是初始化了一个数组,与普通数组一样,都是通过索引也就是下标来查询数组中的元素。

      

2.hashmap的数据存储

        在了解hashmap的存储之前,我们先来看一段代码:

transient Entry[] table;  
static class Entry<K,V> implements Map.Entry<K,V> {          final K key;          V value;          final int hash;          Entry<K,V> next;  ..........  } 
     上图中的entry就是数组中的元素,有key,value 和指向下一个元素的指针,这个指针就构成了链表。

      当我们往hashmap中放入数据的时候,首先会根据当前key的hash值求得该元素在数组中的索引值,如果索引对应的位置没有元素,则直接放入,如果位置上已经有元素了,就会在当前索引的位置上的链表中进行数据存放。

      所以在hashmap的存储结构中,数组的初始作用是根据key的hash值确定元素的存储下标,而链表主要是解决多个元素的插入冲突。当同一个链中的元素超过五个,hashmap将做冲突解决,默认的是使用rehash来再次确定存储位置;

      在对key做hash操作时,其实是一个做 与运算的过程,但是由于直接取模运算性能会比较低,所以hashmap采用的是 长度-1 之后再做与操作,这样就涉及到为什么容量是2的N次方时的访问性能最高,这就涉及到做与运算的操作,做与运算的时候采用的是高位与算法:


      从上图中可以发现,当容量为2的N次方减一 时,长度减一之后的与操作结尾是0 ,这也就意味着末尾是1的存储空间永远不能存储元素,所以造成了空间上的浪费,显然这样会降低查询效率;从这个角度来讲,当存储空间变小之后,碰撞的机率就会加大,也就意味着链表的长度可能要加大,链表一旦长度够长,将会直接影响hashmap的查询速度(因为hashmap的查询需要遍历链表直到找到目标数据,所以时间耗费会长);

3.hashmap的resize

       我们知道当冲突过多,也就是说链表长度足够长时,hashmap会进行扩容,也就是扩大当前的容量。hashmap扩容的标准主要是它自身的一个负载因子loadFactor;负载因子默认是0.75,如果当前的hashmap中元素的个数超过了 容量 * 负载因子就会进行扩容,也就是说,假设当前的容量是16,当数组的占用超过16*0.75,也就是12 的时候就会进行扩容,扩容的基本原则是直接扩充为当前容量的二倍。扩容完成之后,他会将原先hashmap中的数据拷贝到新的hashmap中,所以这里的拷贝成为了hashmap耗费性能的点,所以使用hashmap时我们需要统筹好项目中hashmap的合适容量,尽量避免由扩容引起的性能耗费;

4.线程安全

      在上面的文章中我们提到了hashmap的扩容,了解到扩容中的拷贝引起的

0 0
原创粉丝点击