HashTable的数据结构分析(jdk8)
看了下HashTable的数据结构,继承了Dictionary一个比较过时的抽象类,简单记下原理。
先看下HashTable的成员变量
//存放数据的数组,Entry是HashMap.Node实现的接口,基本类似
private transient Entry<?,?>[] table;
//存放的对象数量
private transient int count;
//扩容阈值
private int threshold;
//hashtable的加载因子
private int threshold;
//操作数
private transient int modCount = 0;
看下存数据的方法
//使用synchronized修饰了put方法
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];
// 如果entry已存在,才会走这里,并且也是hash和key都相同才会认为是相同的,这里没有hashmap的onlyIfAbsent
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
//如果未找到相同的entry 就新增一个
addEntry(hash, key, value, index);
return null;
}
private void addEntry(int hash, K key, V value, int index) {
//操作数加1
modCount++;
Entry<?,?> tab[] = table;
//该扩容了
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
//将新table赋给tab,重新计算hash和index索引
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length;
}
// 新建一个entry放到索引位置
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
// 处理溢出情况
//扩容为2倍+1
int newCapacity = (oldCapacity << 1) + 1;
// 扩容后长度大于0x7fffffff-8
if (newCapacity - MAX_ARRAY_SIZE > 0) {
//如果旧容量已经是最大了,直接返回
if (oldCapacity == MAX_ARRAY_SIZE)
return;
//新容量不会超过最大值
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++;
//扩容阈值,最大不会超过最大值+1
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;
//从数组尾部朝前 重新计算一遍索引 然后放到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;
}
}
}