1、简述
- HashTable 是 Map 接口线程安全版本的实现类,数据结构和方法实现与 HashMap 类似,不过目前基本上被弃用。
2、归纳
- 继承 Dictionary,实现了 Map 接口,实现了 Cloneable 和 Serializable 接口,所以支持复制(拷贝)、序列化。
- 底层是基于数组+单向链表实现的,无序,不可重复,不允许 null 键和 null 值存在。
- 默认初始容量为11,默认负载因子为0.75,扩容时扩容为原来容量的2倍+1。
- 采用 Synchronized 同步锁,锁方法方式锁住了整个 table 保证数据安全,在多线程竞争激烈的情况下效率非常低。
- 单线程安全,多线程安全。
3、分析
3.1、静态内部类
- HashtableEntry 为一个单向链表节点。
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
private static class HashtableEntry<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
HashtableEntry<K,V> next;
protected HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
...
}
...
}
3.2、成员变量
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 1421746759512286392L;
private transient HashtableEntry<?, ?>[] table;
private transient int count;
private int threshold;
private float loadFactor;
private transient int modCount = 0;
...
}
3.3、构造函数
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
public Hashtable() {
this(11, 0.75f);
}
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
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 HashtableEntry<?, ?>[initialCapacity];
threshold = (int) Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
}
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2 * t.size(), 11), 0.75f);
putAll(t);
}
...
}
3.4、增操作
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> entry = (HashtableEntry<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;
}
private void addEntry(int hash, K key, V value, int index) {
modCount++;
HashtableEntry<?, ?> tab[] = table;
if (count >= threshold) {
rehash();
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = (HashtableEntry<K, V>) tab[index];
tab[index] = new HashtableEntry<>(hash, key, value, e);
count++;
}
protected void rehash() {
int oldCapacity = table.length;
HashtableEntry<?, ?>[] oldMap = table;
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
HashtableEntry<?, ?>[] newMap = new HashtableEntry<?, ?>[newCapacity];
modCount++;
threshold = (int) Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
for (int i = oldCapacity; i-- > 0; ) {
for (HashtableEntry<K, V> old = (HashtableEntry<K, V>) oldMap[i]; old != null; ) {
HashtableEntry<K, V> e = old;
old = old.next;
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K, V>) newMap[index];
newMap[index] = e;
}
}
}
...
}
3.5、删操作
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
public synchronized V remove(Object key) {
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = (HashtableEntry<K, V>) tab[index];
for (HashtableEntry<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;
}
@Override
public synchronized boolean remove(Object key, Object value) {
Objects.requireNonNull(value);
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = (HashtableEntry<K, V>) tab[index];
for (HashtableEntry<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;
}
...
}
3.6、改操作
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
@Override
public synchronized V replace(K key, V value) {
Objects.requireNonNull(value);
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = (HashtableEntry<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;
}
@Override
public synchronized boolean replace(K key, V oldValue, V newValue) {
Objects.requireNonNull(oldValue);
Objects.requireNonNull(newValue);
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
HashtableEntry<K, V> e = (HashtableEntry<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;
}
...
}
3.6、查操作
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, java.io.Serializable {
...
public synchronized V get(Object key) {
HashtableEntry<?, ?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (HashtableEntry<?, ?> e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return (V) e.value;
}
}
return null;
}
...
}