相关参数
HashTable底层是基于数组加量表实现的,与HashMap相比,少了红黑树,但是HashTable是线程安全的
//hashtable 地城时基于
//储存节点的数组
private transient Entry<?,?>[] table;
/**
* hashtable中元素的数量
*/
private transient int count;
/**
* 扩展阈值
*/
private int threshold;
/**
* 负载因子
*/
private float loadFactor;
/**
* hashtable结构的修改次数
*/
private transient int modCount = 0;
构造器
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);
}
//有参构造
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
//无参构造
public Hashtable() {
this(11, 0.75f);
}
//有参构造
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t);
}
由无参构造器我们可以看到HashTable的默认数组大小为11,至于为什么是11呢?一会儿再进行解释,我们也可以看到,与HashMap不同的是,数组的初始化是在构造器中完成的。
其他主要代码
/**
* 查询hashtable中是否含有该元素
*/
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;
}
/**
* 判断hashtable中是否含有相应的key值
*/
public synchronized boolean containsKey(Object key) {
Entry<?,?> tab[] = table;
//获得key的hashcode
int hash = key.hashCode();
//计算出相应的数组下标
int index = (hash & 0x7FFFFFFF) % tab.length;
//遍历链表,查找key值
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
return true;
}
}
return false;
}
/**
* 这里解释下为什么初始容量是11,还记得hashmap计算index的公式吗 (n - 1) * & hash,为什么要减1,就是为了保证数组长度尽量为质数,质数的存在会减少hash冲突的概率,hashtable也一样
*/
/**
* 得到相应key 的value值
*/
public synchronized V get(Object key) {
Entry<?,?> tab[] = table;
//得到key的hash
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;
}
/**
* 扩容时调用
*/
protected void rehash() {
//引用旧的数组长度以及数组本身
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
// 对数组进行扩容,为 旧容量*2+1
int newCapacity = (oldCapacity << 1) + 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++;
//新的扩展阈值
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) {
modCount++;
Entry<?,?> tab[] = table;
//判断是否需要扩容
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
//扩容哦那个后重新计算hash值
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++;
}
/**
* 像hashtable中添加值
*/
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// 计算hash值
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;
}