HashMap的工作原理及性能分析

  1. HashMap  
  2.     HashMap的工作原理:  
  3.     HashMap是基于hash算法的原理,使用put(key, value)方法来存储对象,使用get(key)方法来获取对象。  
  4.       
  5.         1,当我们使用put()方法时,需要给它传递一个键值对,然后它调用键的hashCode()方法,返回的hashCode用于找到对应的bucket的位置(即table的下标)来储存Entry对象。  
  6.         如果该key对应的键值对已经存在,则用新的value取代旧的value;返回了旧的value后,直接退出。  
  7.         如果key为null,则将该键值对添加到table[0]中。  
  8.         注:  
  9.             1)当两个entry对象(一个是要新添加进来的对象,一个是已经存在的对象)的Key不同,而entry对象的hash值相同时,就会发生碰撞。HashMap使用链表存储对象,会把新添加的键值对存储在链表头部。  
  10.               
  11.             2)当HashMap中entry数组的实际大小(已放入entry的数量) 大于或等于阈值threshold(threshold = 容量*加载因子loadFactor)时,则  
  12.             将会创建一个是原来entry数组(即table)大小两倍的entry数组,并将原来的entry对象放入新的entry数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置(即table的下标)  
  13.               
  14.             3)在多线程环境下使用HashMap可能导致死锁:  
  15.             如果两个线程都发现HashMap需要重新调整大小了,它们可能会同时试着调整大小。如果条件竞争发生了,那么就死循环了。  
  16.             在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素依次放在链表的尾部,而是依次放在头部,这是为了避免尾部遍历(tail traversing)。  
  17.             故在多线程环境下应该使用ConcurrentHashMap或HashTable  
  18.           
  19.         2,当我们使用get()方法时,需要给它传递一个Key,然后它调用Key的hashCode()方法,返回的hashCode用于找到对应的bucket的位置(即table的下标),然后返回该位置上 hash值和key值均相等 的entry的value值。  
  20.         如果传递的Key为null,则返回table[0]中key为null的entry的value值。如果没有找到,则返回null。  
  21.         注:  
  22.             1)当两个entry对象(一个是要新添加进来的对象,一个是已经存在的对象)的Key不同,而entry对象的hash值相同时,就会发生碰撞。此时,会调用key.equals()方法去找到链表中正确的entry对象的value值  
  23.   
  24.           
  25.     HashMap性能:  
  26.     1)使用String、Interger等包装类适合作为键:  
  27.         String、Interger等包装类是final修饰的类,并且重写了equals()和hashCode()方法。  
  28.         1,因为要计算键的hashCode,就必须保证键的值不会改变。如果一个键的值在放入时的hashcode和获取时的hashcode不同的话,那么就不能从HashMap中找到正确的entry对象。  
  29.         2,键对象正确地重写equals()和hashCode()方法是非常重要的。hashCode()方法应尽量使两个不相等的对象返回不同的hashcode,那么碰撞的几率就会小些,这样HashMap的性能就能提高些。  
  30.            说明:当每个bucket里存储的Entry只是单个Entry ———— 也就是没有通过指针产生Entry链时,此时的 HashMap 具有最好的性能  
  31.         3,键的不可变性使得程序能够缓存不同键的hashcode,这将提高整个获取对象的速度,故HashMap的性能也可提高些。  
  32.         4,String最常用  
  33.         5,键的不可变性也相应地提高了线程安全。  
  34.           
  35.     2)加载因子的大小很重要  
  36.         1,加载因子越大,对空间的利用越充分,但是查找的效率会降低(链表长度会越来越长);  
  37.         2,加载因子太小,那么表中的数据将过于稀疏(很多空间还没用,就开始扩容了),对空间造成严重浪费。  
  38.         3,系统默认加载因子为0.75,这是一个比较理想的值,一般情况下我们是无需修改的。  
  39.           
  40.     3)HashMap中则通过h&(length-1)的方法来代替取模,同样实现了均匀的散列,但效率要高很多。  
  41.         哈希表的容量(entry数组的length)必须是2的整数次幂的原因:  
  42.             1,length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率;  
  43.             2,length为2的整数次幂的话,为偶数,这样length-1为奇数,奇数的最后一位是1,这样便保证了h&(length-1)的最后一位可能为0,也可能为1(这取决于hash值),即:与后的结果可能为偶数,也可能为奇数,这样便保证了散列的均匀性。  
  44.             3,如果length为奇数的话,很明显length-1为偶数,它的最后一位是0,这样h&(length-1)的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,这便浪费了近一半的空间。


原文链接:http://blog.csdn.net/wodewutai17quiet/article/details/46044143
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值