HashMap的工作原理及性能分析

来源:互联网 发布:java主方法入口 编辑:程序博客网 时间:2024/05/08 20:34

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

0 0