HashMap剖析

一、HashMap概述
    HashMap是基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键。(除了不同步和允许使用null之外,HashMap类与HashTable大致相同)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
    HashMap是非同步的,但是我们也可以通过Collections.synchronizedMap(hashMap),使其实现同步。

HashMap其实并不是线程安全的,在高并发的情况下,是很可能发生死循环的,由此造成CPU 100%,这是很可怕的,所以在多线程的情况下,用HashMap是很不妥当的行为,应采用线程安全类ConcurrentHashMap进行代替。


二、HashMap的数据结构
    HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置。HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象多了,就有可能不同对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。
    HashMap其实也是一个线性的数组实现的。HashMap里面实现一个静态内部类Entry,其重要的属性有key、value、next,从属性key、value我们就能很明显看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。
    HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。

三、HashMap源码分析

HashMap类中的一些关键属性:
transient Entry[] table;//存储元素的实体数组
transient int size;//存放元素的个数
int threshold;//临界值 当实际大小超过临界值时,会进行扩容
threshold = 加载因子*容量
final float loadFactor;//加载因子
transient int modCount;//被修改的次数


其中loadFactor加载因子是表示Hash表中元素的填满程度。
    若加载因子越大,填满的元素越多,好处是空间利用率高了,但冲突的机会加大了,链表长度会越来越长,查找效率降低。反之,加载因子越小,填满的元素越少,好处是冲突的机会减少了,但空间浪费多了,表中的数据将过于稀疏(很多空间还没用,就开始扩容了)。
    冲突的机会越大,则查找的成本越高。如果机器内存足够,并且想要提高查询速度的话,可以将加载因子设置小一点;相反如果机器内存紧张,并且对查询速度没有什么要求的话可以将加载因子设置大一点。不过一般我们都不用去设置它,让它取默认值0.75就好了。

    一般对哈希表的散列很自然地会想到用hash值对length取模(即除法散列法),HashTable中也是这样的,这种方法基本能保证元素在哈希表中散列的比较均匀,但取模会用到除法运算,效率很低,HashMap中则通过h&(length-1)的方法来代替取模,同样实现了均匀的散列,但效率要高很多,这也是HashMap对HashTable的一个改进。
    为什么哈希表的容量一定要是2的整数次幂?
    首先,length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率;其次,length为2的整数次幂的话,为偶数,这样length-1为奇数,奇数的最后一位是1,这样便保证了h&(length-1)的最后一位可能为0,也可能为1,即与后的结果可能为偶数,也可能为奇数,这样便可以保证散列的均性。而如果length为奇数的话,很明显length-1为偶数,它的最后一位是0,这样h&(length-1)的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,这便浪费了近一半的空间,因此,length取2的整数次幂,是为了使不同hash值发生碰撞的概率较小,这样就能使元素在哈希表中均匀地散列。

    HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。HashMap底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据hash算法来决定其在数组中的存储位置,再根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。


HashMap包含如下几个构造器:
1、HashMap():构建一个初始容量为16,负载因子为0.75的HashMap。
2、HashMap(int initialCapacity):构建一个初始容量为initialCapacity,负载因子为0.75的HashMap。

3、HashMap(int initialCapacity,float loadFactor):以指定初始容量、指定的负载因子创建一个HashMap。


http://www.cnblogs.com/ITtangtang/p/3948406.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值