Hashtable
基于 数组+链表 实现的线程安全映射
Hashtable继承关系
Hashtable实现了Serializable接口,支持序列化,可通过序列化传输
Hashtable实现了Cloneable接口,覆盖了clone()方法,能被克隆
Hashtable继承了Dictionary抽象类,有映射的基本操作
Hashtable源码分析
静态 类KeySet:
private class KeySet extends AbstractSet<K> {
public Iterator<K> iterator() {
return getIterator(KEYS);
}
public int size() {
return count;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return Hashtable.this.remove(o) != null;
}
public void clear() {
Hashtable.this.clear();
}
}
静态 类EntrySet:
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public Iterator<Map.Entry<K,V>> iterator() {
return getIterator(ENTRIES);
}
public boolean add(Map.Entry<K,V> o) {
return super.add(o);
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
Object key = entry.getKey();
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.equals(entry))
return true;
return false;
}
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
Object key = entry.getKey();
Entry<?,?>[] tab = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
if (e.hash==hash && e.equals(entry)) {
if (prev != null)
// 待删元素e的前一个元素prev的指针指向e的下一个元素next
prev.next = e.next;
else
tab[index] = e.next;
e.value = null; // clear for gc.
modCount++;
count--;
return true;
}
}
return false;
}
public int size() {
return count;
}
public void clear() {
Hashtable.this.clear();
}
}
私有静态 类Entry:
private static class Entry<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Entry<K,V> next;
protected Entry(int hash, K key, V value, Entry<K,V> 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<K,V>) 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();
}
}
私有 类Enumerator:
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
final Entry<?,?>[] table = Hashtable.this.table;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
final int type;
/**
* 指示此Enumerator作为迭代器还是枚举(true -> Iterator)
*/
final boolean iterator;
/**
* The modCount value that the iterator believes that the backing
* Hashtable should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
protected int expectedModCount = Hashtable.this.modCount; // 修改计数
Enumerator(int type, boolean iterator) {
this.type = type;
this.iterator = iterator;
}
public boolean hasMoreElements() {
Entry<?,?> e = entry;
int i = index;
Entry<?,?>[] t = table;
/* Use locals for faster loop iteration */
while (e == null && i > 0) {
e = t[--i];
}
entry = e;
index = i;
return e != null;
}
@SuppressWarnings("unchecked")
public T nextElement() {
Entry<?,?> et = entry;
int i = index;
Entry<?,?>[] t = table;
/* Use locals for faster loop iteration */
while (et == null && i > 0) {
et = t[--i];
}
entry = et;
index = i;
if (et != null) {
Entry<?,?> e = lastReturned = entry;
entry = e.next;
return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
}
throw new NoSuchElementException("Hashtable Enumerator");
}
// Iterator methods
public boolean hasNext() {
return hasMoreElements();
}
public T next() {
if (Hashtable.this.modCount != expectedModCount)
throw new ConcurrentModificationException();
return nextElement();
}
// 删除元素
public void remove() {
if (!iterator)
throw new UnsupportedOperationException();
if (lastReturned == null)
throw new IllegalStateException("Hashtable Enumerator");
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// 同步
synchronized(Hashtable.this) {
Entry<?,?>[] tab = Hashtable.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; // 获取条目索引
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null; e != null; prev = e, e = e.next) {
// 删除迭代器最后返回的条目
if (e == lastReturned) {
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
expectedModCount++;
lastReturned = null;
Hashtable.this.modCount++;
Hashtable.this.count--;
return;
}
}
throw new ConcurrentModificationException();
}
}
}
Hashtable构造函数:
/**
* 使用指定的初始容量和默认负载因子(0.75)构造新的空哈希表
*
* @param initialCapacity the initial capacity of the hashtable.
* @exception IllegalArgumentException if the initial capacity is less
* than zero.
*/
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
/**
* 使用默认的初始容量(11)和默认负载因子(0.75)构造新的空哈希表
*/
public Hashtable() {
this(11, 0.75f);
}
/**
* 使用与给定映射相同的映射和默认的负载因子(0.75)构造新的哈希表
* Hashtable的初始容量足以容纳给定映射中的映射
*
* @param t the map whose mappings are to be placed in this map.
* @throws NullPointerException if the specified map is null.
* @since 1.2
*/
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
/**
* 来自Properties的构造函数保持Hashtable字段未初始化
*
* @param dummy a dummy parameter
*/
Hashtable(Void dummy) {}
Hashtable的其他方法:
/**
* 返回此散列表中键的枚举, 使用返回对象上的枚举方法按顺序获取键
*
* @return an enumeration of the keys in this hashtable.
* @see Enumeration
* @see #elements()
* @see #keySet()
* @see Map
*/
public synchronized Enumeration<K> keys() {
return this.<K>getEnumeration(KEYS);
}
/**
* 返回此散列表中值的枚举, 使用返回对象的枚举方法按顺序获取元素
*
* @return an enumeration of the values in this hashtable.
* @see java.util.Enumeration
* @see #keys()
* @see #values()
* @see Map
*/
public synchronized Enumeration<V> elements() {
return this.<V>getEnumeration(VALUES);
}
/**
* 测试某些键是否映射到此散列表中的指定值
* 这个操作比containsKey方法更昂贵
*
* 此方法在功能上与containsValue相同
*
* @param value a value to search for
* @return {@code true} if and only if some key maps to the
* {@code value} argument in this hashtable as
* determined by the {@code equals} method;
* {@code false} otherwise.
* @exception NullPointerException if the value is {@code null}
*/
public synchronized boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry<?,?> tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
/**
* 测试指定的对象是否是此散列表中的键
*
* @param key possible key
* @return {@code true} if and only if the specified object
* is a key in this hashtable, as determined by the
* {@code equals} method; {@code false} otherwise.
* @throws NullPointerException if the key is {@code null}
* @see #contains(Object)
*/
public synchronized boolean containsKey(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 true;
}
}
return false;
}
/**
* 返回指定键映射到的值, 如果此映射不包含键的映射, 则返回null
* 满足key.equals(k), 则返回e.value
*
* @param key the key whose associated value is to be returned
* @return the value to which the specified key is mapped, or
* {@code null} if this map contains no mapping for the key
* @throws NullPointerException if the specified key is null
* @see #put(Object, Object)
*/
@SuppressWarnings("unchecked")
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;
}
/**
* 增加此散列表的容量并在内部重新组织此散列表
* 当哈希表中的键数超过此哈希表的容量和负载因子时, 自动调用此方法
*/
@SuppressWarnings("unchecked")
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1; // oldCapacity * 2 + 1
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
// 扩容超过最大值则设定为最大值
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
// 阈值 = min(新容量 * 负载因子, hashtable最大容量)
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
// 插入元素
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}
private void addEntry(int hash, K key, V value, int index) {
Entry<?,?> tab[] = table;
if (count >= threshold) { // 当前 > 阈值
// 扩容哈希表
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e); // 插入条目
count++;
modCount++;
}
/**
* 将指定的键映射到此散列表中指定的值
* key 和 value 都不能为null
*
* @param key the hashtable key
* @param value the value
* @return the previous value of the specified key in this hashtable,
* or {@code null} if it did not have one
* @exception NullPointerException if the key or value is
* {@code null}
* @see Object#equals(Object)
* @see #get(Object)
*/
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<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; //若key已存在则更新值, 然后返回旧值
return old;
}
}
addEntry(hash, key, value, index); // 若无则新建一条条目
return null;
}
/**
* 从这个哈希表中删除键(及其对应的值)
*
* @param key the key that needs to be removed
* @return the value to which the key had been mapped in this hashtable,
* or {@code null} if the key did not have a mapping
* @throws NullPointerException if the key is {@code null}
*/
public synchronized V remove(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
modCount++;
count--;
V oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}
/**
* 根据映射接口中的定义返回此映射的散列代码值
*
* @see Map#hashCode()
* @since 1.2
*/
public synchronized int hashCode() {
/*
* This code detects the recursion caused by computing the hash code
* of a self-referential hash table and prevents the stack overflow
* that would otherwise result. This allows certain 1.1-era
* applets with self-referential hash tables to work. This code
* abuses the loadFactor field to do double-duty as a hashCode
* in progress flag, so as not to worsen the space performance.
* A negative load factor indicates that hash code computation is
* in progress.
*/
int h = 0;
if (count == 0 || loadFactor < 0)
return h; // Returns zero
loadFactor = -loadFactor; // Mark hashCode computation in progress
Entry<?,?>[] tab = table;
for (Entry<?,?> entry : tab) {
while (entry != null) {
h += entry.hashCode();
entry = entry.next;
}
}
loadFactor = -loadFactor; // Mark hashCode computation complete
return h;
}
Hashtable总结
Hashtable基于数组和链表实现的存储结构
Hashtable是线程安全的,使用synchronized关键字
Hashtable性能比HashMap低,且不允许插入null元素
Hashtable的初始容量=11,负载因子=0.75
Hashtable每次扩容,新容量=旧容量 * 2 + 1