简单看一下 HashTable 内部结构
public class Hashtableextends Dictionary implements Map , Cloneable, java.io.Serializable { private transient Entry [] table; private transient int count; private int threshold; private float loadFactor; private transient int modCount = 0; public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry [initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } public Hashtable() { this(11, 0.75f); } public Hashtable(Map t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); } public synchronized int size() {...} public synchronized boolean isEmpty() {...} public synchronized Enumeration keys() {...} public synchronized Enumeration elements() {...} public synchronized boolean contains(Object value) {...} public synchronized boolean containsKey(Object key) {...} private static class Entry implements Map.Entry { final int hash; final K key; V value; Entry next; protected Entry(int hash, K key, V value, Entry next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } @SuppressWarnings("unchecked") protected Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry ) next.clone())); } // Map.Entry Ops public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { if (value == null) throw new NullPointerException(); V oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry )o; return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); } public int hashCode() { return hash ^ Objects.hashCode(value); } public String toString() { return key.toString()+"="+value.toString(); } } public synchronized V get(Object key) { Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return (V)e.value; } } return null; } 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; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry entry = (Entry )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; } public synchronized V remove(Object key) { Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry )tab[index]; for(Entry prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; } public synchronized void putAll(Map t) {...} public synchronized void clear() {...} public synchronized Object clone() {...} public synchronized String toString() {...} ....}
看过 HashMap 内部结构之后再来看 HashTable,就会发现结构非常相似。
默认构造方法初始化容量为11,负载因子为0.75,几乎所有的方法都用了 synchronized 修饰了,所有的操作都需要把整个map锁起来,数据是非常安全的,在多线程情况下不会有什么问题,但是性能应该也不怎么样。
HashTable 确定一个数组的位置用的方法为
int index = (hash & 0x7FFFFFFF) % tab.length;
hash 值可能为负数,0x7FFFFFFF的意思是首位为0 剩下的都是1。二进制的第一位为符号为,hash & 0x7FFFFFFF % tab.length 的意思也就是把hash值转换为正数在和tab.length取模,得到数组的位置。
get/put/remove 都是先锁方法,然后通过这个方法获取位置,再对位置上的节点操作。
Java Collections Framework</a>. Unlike the new collection
implementations, { Hashtable} is synchronized. If a thread-safe implementation is not needed, it is recommended to use { HashMap} in place of { Hashtable}. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use { java.util.concurrent.ConcurrentHashMap} in place of { Hashtable}.
这是官网注解,如果不需要线程安全的话,用 HashMap。如果需要线程安全的话,用 ConcurrentHashMap。