基于jdk1.8 HashTable源码解析,put,addEntry, rehash图文

HashTable和HashMap一样,都是通过哈希表实现的,但不同的是,HashTable是线程安全的,在1.8中,它们不一样的地方有很多。
从put方法进入

public synchronized V put(K key, V value) {
        // Make sure the value is not null
	// value值不可以为空
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
	//table即为已存在的数组或者初始化过得数组
        Entry<?,?> tab[] = table;
	//和HashMap不一样的是,这里的hash是hashCode的值
        int hash = key.hashCode();
	//与31个1与操作,对数组长度取余,防止数组下标越界
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
	//遍历,这里的功能是替换重复的key值的value
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
	//没有重复的key值,增加节点
        addEntry(hash, key, value, index);
        return null;
    }

查看增加节点的方法:

private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
	//是否超过阈值,默认阈值是8(就是11*0.75f)
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
	    //超过阈值扩容并改变原来元素的位置
            rehash();

            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
	//将原来下标为index的元素赋值给e
        Entry<K,V> e = (Entry<K,V>) tab[index];
	//将新的节点放在下标为index的位置并将新节点的next设置为e,
	//从这看出来排列的顺序和插入的顺序是相反的
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }

扩容方法:

protected void rehash() {
        int oldCapacity = table.length;
	//旧的数组给oldMap
        Entry<?,?>[] oldMap = table;

        // overflow-conscious code
	// 新的容器大小是原来大小的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;
        }
	// new出新容器,到这新容器还是空的
        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 ; ) {
	    	//旧的元素值给e
                Entry<K,V> e = old;
		//old指向原来元素的下一个元素
                old = old.next;
		
		//给新的元素新的下标,因为没有HashMap设计的精妙,这里的下标位置并没有什么规律
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
		//将新下标位置的元素给e的next,e是原来的old,所以再下一行将e给新的下标位置
		//实际上是将原来的结构反过来,下面给出图文
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }

这是上面for循环的一些过程:
Entry<K,V> e = old;
old = old.next;
在这里插入图片描述
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
在这里插入图片描述
Entry<K,V> e = old;
old = old.next;
在这里插入图片描述
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
在这里插入图片描述
空间有限,凑合看

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值