hashmap数据结构详解(二)之走进JDK源码

 

hashmap数据结构详解(一)之基础知识奠基

hashmap数据结构详解(二)之走进JDK源码

hashmap数据结构详解(三)之hashcode实例及大小是2的幂次方解释

hashmap数据结构详解(四)之hashmap过程综述

hashmap数据结构详解(五)之HashMap、HashTable、ConcurrentHashMap 的区别


在hashmap基础知识奠基之后,一起来走进hashmap的Java代码吧。

走进JDK源码:

 

 

 

       以上是JDK中的接口与实现类。HashMap是继承于(抽象类)AbstractMap,AbstractMap实现了Map接口。下面截图我们看看一个实现类,一个接口里面具体干了什么。

    

 

        HashMap内部也是由节点构成的。节点包括4个属性: HashMap的内部类 包含四个值(next,key,value,hash),其中next是一个指向Node的指针,key相当于上面节点的值 value对应要保存的值,hash值由key产生,hashmap中要找到某个元素,需要根据hash值来求得对应数组中的位置,然后在由key来在链表中找Entry的位置。HashMap中的一切操作都是以Node为基础进行的。HashMap的重点在于如何处理Node。因此HashMap中的操作大部分都是调用Node中的方法。可以说HashMap类本身只是提供了一个数组,和对Node类中方法的一些封装。

 

 

 

  • 然后我们看一下HashMap的构造函数:

 

 

  • 类中定义的静态变量:

 

initialCapacity:

        就是前面所提的左边的数组大小(大小一般为2的指数,后面会解释),数组元素类型是Node类型。

loadFactor:

        表示装填因子,解释:装填因子,以之前我们提到的绿色部分的0—9个空格为例。首先我们需要用hash函数进行第一次装载。此时如果在绿色空格中填入的越多,那么产生冲突的可能性就越大(冲突表示为:该绿色空格被占用,只用作为链表元素),假设绿色部分只使用了8个,那么装填因子为8/10.装填因为越小,那么相对来说产生冲突的可能性较小。

 

        然后我们看看hashmap中几个最常用方法的实现(笔者用的JDK是1.8的,所以里面关于链表部分也存在节点树的应用):

  • 最常用的put

 

 

代码:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
		//hash值是散列值,由散列函数和key决定
		Node<K, V>[] tab;//第一列的数组
		Node<K, V> p;
		int n, i;
		if ((tab = table) == null || (n = tab.length) == 0)//为空则创建第一列数组
			n = (tab = resize()).length;
		if ((p = tab[i = (n - 1) & hash]) == null)
			tab[i] = newNode(hash, key, value, null);//创建一个新的节点,此节点是基槽部分即第一列的节点
		else {
			Node<K, V> e;//创建链表节点
			K k;
			if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
				e = p;//覆盖
			else if (p instanceof TreeNode)//红黑树类型
				e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
			else {//该链为链表
				for (int binCount = 0;; ++binCount) {//binCount表示节点数目
					if ((e = p.next) == null) {
						p.next = newNode(hash, key, value, null);
						if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st,大于了定义的8个节点数
							treeifyBin(tab, hash);//桶的树形化,将之前的链表节点转换为红黑树节点
						break;
					}
					if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
						break;
					p = e;
				}
			}
			if (e != null) { // existing mapping for key,对于已有的键值,直接覆盖
				V oldValue = e.value;
				if (!onlyIfAbsent || oldValue == null)
					e.value = value;
				afterNodeAccess(e);
				return oldValue;
			}
		}
		++modCount;
		// 超过最大容量 就扩容
		if (++size > threshold)
			resize();
		afterNodeInsertion(evict);
		return null;
	}

 

 

 

  •  关于树形化的变量定义

TREEIFY_THRESHOLD

一个桶的树化阈值

UNTREEIFY_THRESHOLD

一个树的链表还原阈值

MIN_TREEIFY_CAPACITY

哈希表的最小树形化容量

当桶中元素个数超过这个值时,需要使用红黑树节点替换链表节点

当扩容时,桶中元素个数小于这个值,就会把树形的桶元素 还原(切分)为链表结构

当哈希表中的容量大于这个值时,表中的桶才能进行树形化 否则桶内元素太多时会扩容,而不是树形化 为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD

 

 

 

  • 树形节点定义:

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值