Java之HashMap

HashMap
  •  Hashmap实际上是一个数组和链表的结合体(在数据结构中,一般称之为“链表散列“)。就是说HashMap是采用链表解决哈希冲突的,而不是开放地址法解决冲突。
  • HashMap的大小和扩张
      size:新建一个HashMap时会初始化一个数组,数组大小默认为16,负载因子默认为0.75。
     也可以使用构造器HashMap(int initialCapacity)来构建一个自定义初始容量,负载因子为 0.75 的 HashMap。这里的自定义初始容量是这样的:取与initialCapacity最相近的2的整数次幂。也可以使用构造器  HashMap(int initialCapacity, float loadFactor) 来指定容量和负载因子。
     resize:对于默认的容量16,负载因子0.75的hashmap而已,当数组中的元素个数超过16*0.75时,冲突变的十分严重,数组要进行扩展,扩展为原来容量的2倍,即为16*2=32,扩张后要重新定位元素在新数组中的位置,消耗比较大。可以采用平摊分析进行复杂度分析。
  • HashMap的存取操作
     : Entry是数组元素,每个Entry对象都是一个<key,value>的键值对,当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
     :在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置 模”运算的消耗还是比较大的,在HashMap中是这样做的:调用 indexFor(int h, int length) 方法来计算该对象应该保存在 table 数组的哪个索引处。indexFor(int h, int length) 方法的代码如下:
  1. static int indexFor(int h, int length) {  
  2.     return h & (length-1);  
  3. }  
    这个方法通过 h & (table.length -1) 来得到该对象的保存位,而HashMap底层数组的长度总是 2 的n 次方,这是HashMap在速度上的优化。
    对于任意给定的对象,只要它的  hashCode()  返回值相同,那么程序调用  hash(int h)  方法所计算得到的  hash 码值总是相同的,而hash值是根据key来计算的,所以在HashMap中不能存在重复的key,但是不同key的value可以相同。
  • fail-fast机制
     我们知道java.util.HashMap不是线程安全的,因此如果在使用迭代器的过程中有其他线程修改了map,那么将抛出 ConcurrentModificationException,这就是所谓fail-fast策略。 这一策略在源码中的实现是通过modCount域,modCount顾名思义就是修改次数,对HashMap内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount。  在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map。
    因此不能在并发场景下使用HashMap。
  • 注意的几点:
     HashMap中允许key和value是null;
    在迭代时,按照数组的index从0到length-1遍历,把不为null的数据取出来;
    在HashMap中不能存在重复的key,但是不同key的value可以相同。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值