java开发:集合(六):HashTable源码分析

上次对hashMap进行了源码分析我们知道hashMap是非线程安全的,其次hashMap允许key值为null,且只有一个。这次我们对HashTable进行分析,看看hashMap和HashTable的区别在哪。

1.HashTable是线程安全的

synchronized void                clear()
synchronized Object              clone()
             boolean             contains(Object value)
synchronized boolean             containsKey(Object key)
synchronized boolean             containsValue(Object value)
synchronized Enumeration<V>      elements()
synchronized Set<Entry<K, V>>    entrySet()
synchronized boolean             equals(Object object)
synchronized V                   get(Object key)
synchronized int                 hashCode()
synchronized boolean             isEmpty()
synchronized Set<K>              keySet()
synchronized Enumeration<K>      keys()
synchronized V                   put(K key, V value)
synchronized void                putAll(Map<? extends K, ? extends V> map)
synchronized V                   remove(Object key)
synchronized int                 size()
synchronized String              toString()
synchronized Collection<V>       values()

从源码可以看到hashTable相关的方法都是加上了synchronized 同步锁,多线程访问的时候需要拿到同步锁才能访问。

java开发:集合(四):hashMap源码解析
Java开发:java多线程(一):synchronized 对象锁和类锁的区别

2.hashTable的key值和value不能为空
hashTable:

public synchronized V put(K key, V value) {
	//确保value不为空
	if (value == null) {
		throw new NullPointerException();
	}
 
	Entry tab[] = table;
	int hash = hash(key); //计算哈希值
	int index = (hash & 0x7FFFFFFF) % tab.length; //根据哈希值计算在数组中的索引
	for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
		if ((e.hash == hash) && e.key.equals(key)) { //如果对应的key已经存在
			V old = e.value;
			e.value = value; //替换掉原来的value
			return old;
		}
	}
	//否则新添加一个Entry
	modCount++;
	if (count >= threshold) { //判断数组中的Entry数量是否已经达到阈值
		rehash(); //如果达到了,扩容
 
		tab = table;
		hash = hash(key); //重新计算哈希值
		index = (hash & 0x7FFFFFFF) % tab.length; //重新计算在新的数组中的索引
	}
 
	//创建一个新的Entry
	Entry<K,V> e = tab[index];
	//存到对应的位置,并将其next置为原来该位置的Entry,这样就与原来的连上了
	tab[index] = new Entry<>(hash, key, value, e);
	count++;
	return null;
}

hashMap

 public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        //计算key的哈希值
        int hash = hash(key);
        //根据key哈希值和数组长度计算出存储下标
        int i = indexFor(hash, table.length);
        //历遍table[i]整个链表,如果出现key重复的则覆盖value值,然后return结束程序
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        //上面的for循环结束后没有发现key没有重复则会执行这个方法
        addEntry(hash, key, value, i);
        return null;
    }


 private V putForNullKey(V value) {
 		//获取数组的第一个位置元素,历遍链表找到key为null的键值对然后覆盖value值
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                //结束方法
                return oldValue;
            }
        }
        modCount++;
        //上面的for循环结束后没有发现key为null的元素则会执行这个方法
        addEntry(0, null, value, 0);
        return null;
    }

	
  void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
		//创建节点
        createEntry(hash, key, value, bucketIndex);
    }
    
 void createEntry(int hash, K key, V value, int bucketIndex) {
 		//根据bucketIndex获取数组指定位置的元素,e 是链表的头结点
        Entry<K,V> e = table[bucketIndex];
        //创建节点放到数组中,这时候该节点成为头结点,同时它的next指向上一个头结点e
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

对比hashMap和hashTable的put方法可以发现有如下区别:
1.hashMap会对key判断null值,为null的话直接把元素插到table[0]对应的链表,然后历遍链表查看有没有key为null的元素,有则覆盖,无则添加。因此hashMap只能有一个key值可以为null
2.hashTable则是先对value值判断null值,为null直接抛出空异常。接着根据key计算哈希值找到在数组的映射索引,那如果key=null的话计算哈希值的时候也直接会报空异常。因此hashTable的key和value都不能为空,hashMap的key和value都可以为空,且key只能有一个为空。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值