Java的HashMap和HashTable

1. HashMap算法

1)  hashmap的数据结构 数组

     Hashmap是一个数组和链表的结合体(在数据结构称“链表散列“),以下图示安全

当咱们往hashmap中put元素的时候,先根据key的hash值获得这个元素在数组中的位置(即下标),而后就能够把这个元素放到对应的位置中了。若是这个元素所在的位子上已经存放有其余元素了,那判断该位置上有没有与当前key相等(equals)的元素,若是有则替换该元素的value值,若是尚未那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最早加入的放在链尾。数据结构

key的hash值的算法:
性能

   a、 当调用put(key,value)时,首先获取key的hashcode,int hash = key.hashCode(); spa

   b、 再把hash经过一下运算获得一个int h.  hash ^= (hash >>> 20) ^ (hash >>> 12); 线程

    int h = hash ^ (hash >>> 7) ^ (hash >>> 4); code

为何要通过这样的运算呢?这就是HashMap的高明之处。先看个例子,一个十进制数32768(二进制1000 0000 0000 0000),通过上述公式运算以后的结果是35080(二进制1000 1001 0000 1000)。看出来了吗?或许这样还看不出什么,再举个数字61440(二进制1111 0000 0000 0000),运算结果是65263(二进制1111 1110 1110 1111),如今应该很明显了,它的目的是让“1”变的均匀一点,散列的本意就是要尽可能均匀分布。那这样有什么意义呢?看第3步。 orm

    c、 获得h以后,把h与HashMap的承载量(HashMap的默认承载量【即上图中数组的长度length是16,能够自动变长。在构造HashMap的时候也能够指定一个长 度。这个承载量就是上图所描述的数组的长度。)进行逻辑与运算,即 h & (length-1),这样获得的结果就是一个比length小的正数,咱们把这个值叫作index。其实这个index就是索引将要插入的值在数组中的 位置。第b步那个算法的意义就是但愿可以得出均匀的index,这是HashTable的改进,HashTable中的算法只是把key的 hashcode与length相除取余,即hash % length,这样有可能会形成index分布不均匀。还有一点须要说明,HashMap的键能够为null,它的值是放在数组的第一个位置。 对象

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,但决定用哪个以前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。JDK1.5之后HashTable能够用ConcurrentHashMap来代替。

  1. HashMap几乎能够等价于Hashtable,除了HashMap是非synchronized的,并能够接受null(HashMap能够接受为null的键值(key)和值(value),而Hashtable则不行)。

  2. HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程能够共享一个Hashtable;而若是没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

  3. 另外一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。因此当有其它线程改变了HashMap的结构(增长或者移除元素),将会抛出ConcurrentModificationException,但迭代器自己的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并非一个必定发生的行为,要看JVM。这条一样也是Enumeration和Iterator的区别。

  4. 因为Hashtable是线程安全的也是synchronized,因此在单线程环境下它比HashMap要慢。若是你不须要同步,只须要单一线程,那么使用HashMap性能要好过Hashtable。

  5. HashMap不能保证随着时间的推移Map中的元素次序是不变的。

要注意的一些重要术语:

1) sychronized意味着在一次仅有一个线程可以更改Hashtable。就是说任何线程要更新Hashtable时要首先得到同步锁,其它线程要等到同步锁被释放以后才能再次得到同步锁更新Hashtable。

2) Fail-safe和iterator迭代器相关。若是某个集合对象建立了Iterator或者ListIterator,而后其它的线程试图“结构上”更改集合对象,将会抛出ConcurrentModificationException异常。但其它线程能够经过set()方法更改集合对象是容许的,由于这并无从“结构上”更改集合。可是假如已经从结构上进行了更改,再调用set()方法,将会抛出IllegalArgumentException异常。

3) 结构上的更改指的是删除或者插入一个元素,这样会影响到map的结构。

咱们可否让HashMap同步?

HashMap能够经过下面的语句进行同步:
Map m = Collections.synchronizeMap(hashMap);

结论

Hashtable和HashMap有几个主要的不一样:线程安全以及速度。仅在你须要彻底的线程安全的时候使用Hashtable,而若是你使用Java 5或以上的话,请使用ConcurrentHashMap吧。

相关文章
相关标签/搜索