java之HashMap结构put()方法源码分析

数据结构是java学习中很重要的一部分,HashMap也是数据结构中很常用的一部分。我们将通过源码对HashMap的方法和结构进行分析和理解。
为了能让我的理解和源码能更明白清晰的呈现出来,我将使用代码和解析一起的方式展示给大家。另外,这只是我个人的理解和分析,大家可以先看一下再去找更清晰准确的文章进行深入理解。我看到一篇不错的文章就链接给大家吧。我目前仅仅分析了基本的put()方法的源码,至于红黑树,链表之后再给大家详细分析。
转自zju_jzb的博客

//HashMap的put方法源代码以及个人理解解析
	/*
	 * 基本思想:
	 * 在hashmap中底层是数组+链表式存储
	 * 先是按照key值进行hash作为存储地址在结构中进行寻找
	 * 找到后先看该地址是否为空,如果为空则直接存储就可以
	 * 如果不为空,就表示该地址已经存储元素,就需要进行覆盖
	 * 
	 */
	 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)
	  {
		 
		  Node<K,V>[] tab; Node<K,V> p; int n, i;
		  /*
		   * 定义变量,tab表示节点数组,是哈希桶数组(可以用来存储hashmap
		   * 对应的key,value对节点元素)
		   * p表示节点;n表示数组长度;i表示数组下标;
		   */
		  
		  if ((tab = table) == null || (n = tab.length) == 0)
			  /*
			   * table实际上也代表节点数组
			   * 该语句判断数组是否为空,或者长度为0
			   */
			  
		      n = (tab = resize()).length;
		  //如果是那么重新定义数组的长度,resize表示重新定义长度
		  
		  if ((p = tab[i = (n - 1) & hash]) == null)
			  /*
			   * 该语句使用i = (n - 1) & hash的位运算方式来确定数组下标,
			   * 将这个下标位置的节点元素赋值给p,判断p是否为空
			   * (实际也就是判断要插入的元素hash后的地址是否已存在元素)
			   */
			  
		      tab[i] = newNode(hash, key, value, null);
		  //如果为空表示该地址没有存储元素,可以直接创建一个新的节点元素进行存储
		  
		  else {
			  /*否则表示该地址已经存在元素,
			   * 以及当两者key值相等时执行覆盖操作
			   */
			  
		      Node<K,V> e; K k;
		      /*
		       * 定义变量,e表示节点元素,k从下面k = p.key语句可以看出表示p的key值
		       */
		      
		      if (p.hash == hash &&
		          ((k = p.key) == key || (key != null && key.equals(k))))
		    	  /*
		    	   * 判断hash值是否相同,并且同时判断key是否equals
		    	   */
		    	  
		          e = p;
		      //如果满足那么先将p节点元素赋值给e,
		      //因为后面可能还会对相同key值的节点进行操作,
		      //我们放到最后再进行覆盖或者链表,红黑树插入
		      
		      ***//下面是红黑树节点***
		      else if (p instanceof TreeNode)
		    	  /*
		    	   * 判断p的是否是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的下一个元素是null,表示已经到头了
		            	   */
		            	  
		                  p.next = newNode(hash, key, value, null);
		                  //直接在链表结尾增加新元素
		                  
		                  if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
		                	  /*
		                	   * 判断计数值是否还
		                	   */
		                      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
		    	  /*
		    	   * 如果key值相同。接下来就要进行覆盖
		    	   * 在e节点不为空的前提下进行下列操作
		    	   */
		    	  
		          V oldValue = e.value;
		          //变量创建及赋值,将e节点的value值赋值给变量oldValue
		          
		          if (!onlyIfAbsent || oldValue == null)
		        	  /*
		        	   * 判断是否进行覆盖操作,
		        	   * onlyIfAbsent实际上就是控制是否进行覆盖操作,
		        	   * 如果为true不进行覆盖,false进行覆盖
		        	   * 当onlyIfAbsent为false或者oldValue为null时进行下面操作
		        	   */
		              e.value = value;
		          //进行覆盖操作
		          afterNodeAccess(e);
		          //空函数
		          
		          return oldValue;
		          //返回oldValue
		      }
		  }
		  ++modCount;
		  if (++size > threshold)
			  /*
			   * 判断是否还能装的下,是否应该扩容
			   */
		      resize();
		  /*
		   * 如果是,那么进行扩容
		   */
		  afterNodeInsertion(evict);
		  return null;
		  //返回空值。
		}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章