Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,不允许value值为null,采用单向链表的形式。具体操作与单向链表相同。
源码分析
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {
//hashtable 的数据
private transient Entry<?,?>[] table;
//哈希表中的条目总数。
private transient int count;
//当其大小超过此阈值时,表被重新打开。 (该字段的值为(int)(capacity * loadFactor)。)
private int threshold;
//哈希表的负载因子。
private float loadFactor;
private transient int modCount = 0;
private static final long serialVersionUID = 1421746759512286392L;
//构造一个新的,空的散列表,具有指定的初始容量和指定的负载因子。
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);
}
//构造一个新的空的散列表,具有指定的初始容量和默认负载因子(0.75)。
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
//构造一个新的,空的散列表,默认的初始容量(11)和负载因子(0.75)。
public Hashtable() {
this(11, 0.75f);
}
//使用与给定地图相同的映射构造新的散列表。 创建散列表的初始容量足以容纳给定地图中的映射和默认负载因子(0.75)。
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
//返回此哈希表中的key的数量
public synchronized int size() {
return count;
}
//测试这个哈希表是否将值映射到值。
public synchronized boolean isEmpty() {
return count == 0;
}
//返回此散列表中键的枚举。
public synchronized Enumeration<K> keys() {
return this.<K>getEnumeration(KEYS);
}
//返回此散列表中值的枚举。 对返回的对象使用枚举方法来顺序获取元素。
public synchronized Enumeration<V> elements() {
return this.<V>getEnumeration(VALUES);
}
//测试一些键映射到这个散列表中的指定值。 此操作比containsKey方法更昂贵。
//请注意,此方法的功能与containsValue(它是集合框架中的Map接口的一部分)的功能相同。
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;
}
//如果此哈希表将一个或多个键映射到此值,则返回true。
//请注意,此方法的功能与contains的功能相同。
public boolean containsValue(Object value) {
return contains(value);
}
//测试指定的对象是否在此哈希表中的键。
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到value的映射,使得(key.equals(k)),则该方法返回value; 否则返回null。(最多可以有一个这样的映射。)
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
int hash = key.hashCode();
//计算索引值
int index = (hash & 0x7FFFFFFF) % tab.length;
//在key对应的Entry链表下,找到hash和key值与输入可以都相等的元素
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V)e.value;
}
}
return null;
}
//要分配的数组的最大大小。 一些虚拟机在阵列中保留一些头文字。
//尝试分配较大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//增加这个散列表的内部重组能力,从而更有效地适应和访问其条目。
//当哈希表中的键数超过此散列表的容量和负载因子时,将自动调用此方法。
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
//新容量的大小设置为旧容量的两倍加一
int newCapacity = (oldCapacity << 1) + 1;
//如果旧容量等于最大容量,新容器容量超过最大容量,将容量保持到最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
//创建新的Entry链表
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
//统计数+1
modCount++;
//重新计算阙值大小
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
//将旧的hashtable的内容复制到新的hashtable中
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
//将next往前移动一个位置
old = old.next;
//重新计算索引值
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
//将e的next元素指向新的hashtable中索引链表的首元素
e.next = (Entry<K,V>)newMap[index];
//将e复制到新的hashtable中,作为链表的首元素,之前新hashtable中的元素往后移动一个位置
newMap[index] = e;
}
}
}
private void addEntry(int hash, K key, V value, int index) {
modCount++;
//获取hashtable
Entry<?,?> tab[] = table;
if (count >= threshold) {
//如果超过阈值,则重新排列表
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
//创建一个新的Entry
Entry<K,V> e = (Entry<K,V>) tab[index];
//将e连接在插入Entry的next
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
/将指定的key映射到此散列表中指定的value。 key和value都不能是null。
//可以通过使用等于原始key的key调用get方法来检索该值。
public synchronized V put(K key, V value) {
//确保value不为null
if (value == null) {
throw new NullPointerException();
}
//确保key不在哈希表中。
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
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;
}
}
//如果没有key和hash匹配的元素,则创建并添加新的entry
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;
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)) {
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<? extends K, ? extends V> t) {
for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
put(e.getKey(), e.getValue());
}
//清除此散列表,使其不包含键。
public synchronized void clear() {
Entry<?,?> tab[] = table;
modCount++;
for (int index = tab.length; --index >= 0; )
tab[index] = null;
count = 0;
}
//创建这个散列表的浅拷贝。 哈希表本身的所有结构都被复制,但是键和值不被克隆。 这是一个相对昂贵的操作。
public synchronized Object clone() {
try {
Hashtable<?,?> t = (Hashtable<?,?>)super.clone();
t.table = new Entry<?,?>[table.length];
for (int i = table.length ; i-- > 0 ; ) {
t.table[i] = (table[i] != null)
? (Entry<?,?>) table[i].clone() : null;
}
t.keySet = null;
t.entrySet = null;
t.values = null;
t.modCount = 0;
return t;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
//根据Map界面中的定义,将指定的对象与此Map进行比较以相等。
public synchronized boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<?,?> t = (Map<?,?>) o;
if (t.size() != size())
return false;
try {
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Map.Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(t.get(key)==null && t.containsKey(key)))
return false;
} else {
if (!value.equals(t.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
//将每个条目的value替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。
public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function); // 需要明确检查
final int expectedModCount = modCount;
Entry<K, V>[] tab = (Entry<K, V>[])table;
for (Entry<K, V> entry : tab) {
while (entry != null) {
entry.value = Objects.requireNonNull(
function.apply(entry.key, entry.value));
entry = entry.next;
if (expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
}
//如果指定的key还没有与value相关联(或映射到null)将其与给定value相关联并返回null,否则返回当前value。
public synchronized V putIfAbsent(K key, V value) {
Objects.requireNonNull(value);
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
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;
if (old == null) {
entry.value = value;
}
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
//只有当目标映射到指定的值时,才能删除指定key的条目。
public synchronized boolean remove(Object key, Object value) {
Objects.requireNonNull(value);
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) && e.value.equals(value)) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
e.value = null;
return true;
}
}
return false;
}
//仅当当前映射到指定的value时,才能替换指定key的条目。
public synchronized boolean replace(K key, V oldValue, V newValue) {
Objects.requireNonNull(oldValue);
Objects.requireNonNull(newValue);
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 (; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
if (e.value.equals(oldValue)) {
e.value = newValue;
return true;
} else {
return false;
}
}
}
return false;
}
//只有当目标映射到某个值时,才能替换指定键的条目。
public synchronized V replace(K key, V value) {
Objects.requireNonNull(value);
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 (; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
return null;
}
//如果指定的键尚未与值相关联(或映射到null),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非为null。
public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
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 (; e != null; e = e.next) {
if (e.hash == hash && e.key.equals(key)) {
// Hashtable not accept null value
return e.value;
}
}
V newValue = mappingFunction.apply(key);
if (newValue != null) {
addEntry(hash, key, newValue, index);
}
return newValue;
}
//如果指定的键的值存在且非空,则尝试计算给定键的新映射及其当前映射的值。
public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
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)) {
V newValue = remappingFunction.apply(key, e.value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
} else {
e.value = newValue;
}
return newValue;
}
}
return null;
}
//尝试计算指定key及其当前映射value的映射(如果没有当前映射,则为null)。
public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
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 && Objects.equals(e.key, key)) {
V newValue = remappingFunction.apply(key, e.value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
} else {
e.value = newValue;
}
return newValue;
}
}
V newValue = remappingFunction.apply(key, null);
if (newValue != null) {
addEntry(hash, key, newValue, index);
}
return newValue;
}
//如果指定的key尚未与value相关联或与null相关联,则将其与给定的非空值相关联。
public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
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)) {
V newValue = remappingFunction.apply(e.value, value);
if (newValue == null) {
modCount++;
if (prev != null) {
prev.next = e.next;
} else {
tab[index] = e.next;
}
count--;
} else {
e.value = newValue;
}
return newValue;
}
}
if (value != null) {
addEntry(hash, key, value, index);
}
return value;
}
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();
}
}
// Types of Enumerations/Iterations
private static final int KEYS = 0;
private static final int VALUES = 1;
private static final int ENTRIES = 2;
//一个哈希表枚举器类。 此类实现了枚举和迭代器接口,但是可以使用禁用Iterator方法创建单个实例。
//这是必要的,以避免无意中通过传递枚举来增加用户授予的功能。
private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
Entry<?,?>[] table = Hashtable.this.table;
int index = table.length;
Entry<?,?> entry;
Entry<?,?> lastReturned;
int type;
//指示此枚举器是否用作迭代器或枚举。 (true - >迭代器)。
boolean iterator;
//迭代器认为后台Hashtable应该具有的modCount值。 如果这个期望被违反,迭代器就检测到并发修改。
protected int expectedModCount = 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 (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) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
}
}
rehash过程中,hashtable旧元素的复制过程: