java—HashMap与Hashtable的源码比较
2017-11-01 15:59
609 查看
java—HashMap与Hashtable的源码比较
本文主要记录通过源码阅读的方式比较HashMap和HashTable1. HashMap、HashTable的类结构
HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
HashMap继承于AbstractMap,Hashtable继承于Dictionary。
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable
通过查阅jdk,有下面这句话:
NOTE: This class is obsolete. New implementations should implement the Map interface, rather than extending this class.
得知Dictionary类已经过时了,而推荐实现Map接口。
而Hashtable也是一个过时的集合类,从jdk1.0开始就存在了。在Java 4中被重写了,实现了Map接口,所以自此以后也成了java集合框架的一部分。
2. 主要区别
1. 线程安全性
HashMap是线程不安全的,Hashtable是线程安全的。Hashtable的线程安全是用synchronized关键字实现的。public synchronized int size(); public synchronized boolean isEmpty(); public synchronized V get(Object key); public synchronized V put(K key, V value);
以上方法是Hashtable源码里的,其实和HashMap几乎一样,只是多了synchronized关键字。则Hashtable是线程安全的,多个线程可以共享一个Hashtable。而如果没有正确同步的话,多个线程不能共享HashMap。Java 5 提供了ConcurrentHashMap,它是Hashtable的替代,比Hashtable的扩展更好
2. null的键和值
HashMap是可以接受null的键和值的,而Hashtable则不允许。先从Hashtable的put()方法讲起:
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry<!--?,? > tab[] = table;<br ?--> int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)tab[index]; for(; entry != null ; entry = entry.next) { if ((entry.hash == hash) && entry.key.equals(key)) { V old = entry.value; entry.value = value; return old; } } addEntry(hash, key, value, index); return null; }
在put()方法里,首先会对value进行检查,若为null,则抛出NullPointerException。对于key,则直接使用key.hashcode(),若key为null,则仍会抛出NullPointerException。
下面再看下HashMap里的put()实现:
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
put()会调用putVal(),而putVal()中则不会对value做null的检查,再看看key,是如果获得null值的key的hash值。这是用到了HashMap里的hash()。
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
很明显,若key为null,则hash值用0。这便是HashMap如何支持null值的key和value。
3. 速度
Hashtable是线程安全的,所以在单线程环境下它比HashMap要慢。如果不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。3. 让HashMap同步
HashMap可以通过下面的语句进行同步:Map m = Collections.synchronizeMap(hashMap);
实现方法仍然是给方法加上synchronized关键字。
public int size() { synchronized (mutex) {return m.size();} } public boolean isEmpty() { synchronized (mutex) {return m.isEmpty();} } public boolean containsKey(Object key) { synchronized (mutex) {return m.containsKey(key);} } public boolean containsValue(Object value) { synchronized (mutex) {return m.containsValue(value);} } public V get(Object key) { synchronized (mutex) {return m.get(key);} } public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} } public V remove(Object key) { synchronized (mutex) {return m.remove(key);} } public void putAll(Map<? extends K, ? extends V> map) { synchronized (mutex) {m.putAll(map);} } public void clear() { synchronized (mutex) {m.clear();} } private transient Set keySet; private transient Set<Map.Entry<K,V>> entrySet; private transient Collection values; public Set keySet() { synchronized (mutex) { if (keySet==null) keySet = new SynchronizedSet<>(m.keySet(), mutex); return keySet; } }
4. 疑惑
看别人的文章里说,HashMap和HashTable的迭代器是不同的,HashMap用的是iterator是fail-fast的,而HashTable用的是enumerator不是fail-fast的。但我看1.8jdk里的Hashtable的enumerator 如下:private class Enumerator implements Enumeration, Iterator
是有实现iterator接口的,也就是Hashtable其实是iterator和Enumeration都有支持的。
后续再补充吧。对于fail-fast还是没透彻理解。
相关文章推荐
- 集合源码学习(十):HashTable(Java8)与HashMap比较
- Java集合源码学习笔记(五)ArrayList,LinkedList,Vector和Hashtable,HashMap的比较
- Java集合(17)--HashMap、Hashtable和ConcurrentHashMap的比较
- 看看源码怎么处理,Java中Hashtable,Hashmap,ConcurrentHashMap,Key Value为null时
- Java:Map与HashMap,Hashtable,HashSet比较
- java1.7集合源码赏析系列:HashTable、ConcurrentHashMap、HashMap差异分析
- HashMap,Hashtable以及ConcurrentHashMap的比较(源码)
- Java:Map与HashMap,Hashtable,HashSet比较
- java集合(ArrayList、vector、HashMap、HashTable)源码剖析
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
- Java中的Copy-on-Write容器 & ConcurrentHashMap & HashTable比较
- Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较
- Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较
- 面试Java基础之HashMap、Hashtable、WeakHashMap比较
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
- HashMap,Hashtable以及ConcurrentHashMap的比较(源码)
- Java:Map与HashMap,Hashtable,HashSet比较
- Java中Hashtable,HashMap,WeakHashMap比较
- java中的几种泛型类——HashSet、HashMap、TreeSet、TreeMap,遍历map,排序,HashTable比较
- Java集合——HashMap、HashTable以及ConCurrentHashMap异同比较