1 概述
- HashTable继承自抽象类Dictionary, 并实现了Map接口,实际上,Map接口就是用来代替Dictionary
- 是一个线程安全的Map
- key和value均不允许为null
- 为了正确使用Hashtable存取key-value对,用作key的类必须实现hashcode()和equals()方法
- 初始化用的 initial capacity 和 load factory(默认为0.75) 会影响HashTable的性能
2 底层实现
- 五个私有变量
- transient Entry,?>[] table HashTable实际维护的容器,一个Entry数组
- transient int count 容器存储key-value对的总数
- int threshold 扩容标志, 当容器的size()大于这个值时,会进行rehash操作——扩容并重新组织table
- float loadFactor 扩容因子,扩容相关
- transient int modCount = 0 一个标志,每次修改容器内容modCount就会自增,主要用于遍历时判断是否容器是否在被其他对象修改, 如果modeCount在遍历时发生变化,就会抛出异常
- 初始化
- 基本的构造器HashTable(int initialCapacity, float loadFactor),
table实际是HashTable里一个静态私有类Entry<K, V>数组,Entry<K, V> 实现了Map.Entry<K, V> 接口
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);
}
- HashTable(int initialCapacity) 默认 loadFactory 为 0.75
- HashTable() 默认 initialCapacity 为 11, loadFactory 为 0.75
- HashTable(Map map) 默认 initialCapacity 为 max(2*map.size(),11), loadFactory 为0.75
- 静态私有类 Entry<K, V>,不难看出实际上这是一个单向链表
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;
}
}
public synchronized V put(K key, V value) {
if (value == null) {
throw new NullPointerException();
}
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;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
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;
}
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
modCount++;
}
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<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
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;
}
}
}
- get(Object key) 实际上就是put(key,value)中的一段
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;
}
3 总结
- HashTable的主要方法都使用synchronized关键字修饰来保证其线程安全
- 底层使用哈希表实现
- 因为有 HashMap 和 ConcurrentMap的存在,被用得很少,但是我们常用的Properties类是通过继承HashTable来实现的