Hashtable源码分析

转自https://blog.csdn.net/duoduo18up/article/details/80167074

1.定义

public class Hashtable<K,V> 
    extends Dictionary<K,V>
    implements Map<K,V>,Cloneable,java.io.Serializable

继承自Dictionary。

  • Dictionary是一个抽象父类,功能和Map一样,但过时了,官方推荐使用Map接口来替代。

实现了Map接口,以及Cloneable,Serializable接口。

2.和HashMap的区别

2.1 null值的问题

Hashtable的键(key)和值(value)均不能为null

/**     
* 将key和value加入到map中,明显标明,
* value不能为null。如果key为null,则会报NullPointerException异常 
* */
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();
	//很直接的利用hashCode去除table.length,然后取长度。
	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)) {
			//hash相同且equals,那么就连在后面,是用链表的方式。
			V old = entry.value;
			entry.value = value;
			return old;
			}
		}
	//第一个,链表后面没有数据。
	addEntry(hash, key, value, index);
	return null;
}

关于value,明显有if判断,不能为null。

如果key为null,则也直接在计算hashCode的时候就会报空指针异常。

2.2 计算table数组索引值的方法

int hash=key.hashCode();//直接用hashcode%n
int index=(hash&0x7FFFFFFF)%tab.length

而HashMap中:

int index=e.hash%n;

hash值的计算方法不同,很直接地利用hashCode去除table.length,然后取余数。

2.3 Hashtable是线程安全的

因为Hashtable中的大多数方法都是加了synchronized关键字,所以同一时刻只能有一个线程进入其方法,故是线程安全的。

2.4initialCapacity和loadFactor

HashMap中:initialCapacity=16,loadFactor=0.75;

Hashtable中:initialCapacity=11,loadFactor=0.75;

2.5解决冲突的方式

HashMap:链表/红黑树

  • 冲突数量<8,以链表方式解决冲突
  • 冲突数量>=8,将冲突的Entry转换为红黑树进行存储
  • 又当冲突数量<6时,有转换为链表进行存储

Hashtable:只有链表

2.6 扩容的额度

HashMap中:一旦扩容,都是扩展到2的倍数。因为这样有利于计算数组索引值。即,和计算数组索引结合起来

Hashtable中:一次性扩展为oldCapacity*2+1

/**
 * 一次扩展是,old*2+1
*/
@SuppressWarnings("unchecked")
protected void rehash() {
	int oldCapacity = table.length;
	Entry<?,?>[] oldMap = table;
	// overflow-conscious code
	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值。取newCapacity*loadFactor的小值。
	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;
		}
	}
}

先扩展,再把就数组里面的元素一个一个添加到新的里面。

注意:这里取hash而不是e.hash,而仍然是key.hashCode计算保留下来的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值