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;
		  //返回空值。
		}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章