HashSet新增操作底層判讀(Object型別)

發表於2021-05-11

Object型別新增操作判讀

 

 

 第一步:程式首先建立一個Object泛型的Set陣列,這裡用到了上轉型;

第二步:執行object裡面的add新增方法,傳進的值為“JAVA”;

首先HashSet原始碼中會有HashSet的無參構造方法:說明只要建立一個HashSet陣列就會預設建立一個HashMap陣列

 

因為Set的add方法被HashSet重寫過,所以執行時add會執行HashSet的add方法,此時我們開啟HashSet中add方法:

 

 

 此時引數e為剛剛傳進的”JAVA“。

可以看到add方法呼叫的map裡面的put方法,傳入e和一個常量(常量全大寫),判斷是不是null(空)。

此時我們進入map裡的put方法:

 

 

 此時可以看到put需要的引數為key值和value對應剛剛傳入的e和一個常量,此時可以看到put裡面呼叫的是putVal方法,

傳入的值為hash(key),key,value,false,true。此時開啟引數列表中hash(key)方法來檢視hash(key)的值到底是個什麼樣的值:

 

 

 hash方法傳進來的引數為key為e也就是”JAVA“,這裡為三目運算,若為空返回0,不為空返回一個”JAVA“特定的hashCode然後在被處理的值

此時搞明白引數列表我們就需要檢視putVal方法體:

 

 

 引數hash,key,value,onlyIfAbsent,evict

其中hash隨你key引數變化而變化,key為你要存入的資料(”JAVA“),後三位為常量 false true;

第一步 建立tab,p陣列和int型別的n和i:

進入判斷語句

將table地址值賦值給tab ,table為一個全域性變數預設值為null,而且後邊判斷條件也成立,直接進入方法體

此時需要進入resize方法:

 

 oldTab為空陣列,oldCap為0,oldThr為0,建立兩個變數為0;

隨後經過判斷預計進入:

 

 此時newCap為16,作用為陣列預設容量初始為16;後面常量為16;newThr為16*0.75作用為0.75倍擴容

此後進入

 

 下一步:

 

 長度為16的陣列,下一步返回

 

 長度為16的空陣列,此時走完resize()方法,回到putVal

 

 

 

 此時n為16此時進入下一不判斷語句:

 

用來判斷tab中i = (n - 1) & hash]位元素是否為空,此時為空,賦給tab中i為元素為newNode,newNode方法體為:

 

 此時tab第i為有值了,然後程式接著走:

 

 最後返回一個null給呼叫它的put方法:

 

 

put也返回null給呼叫它的方法add:

 

 判斷為true,此時返回給objects陣列true新增成功:

 

 

到此新增程式結束。

 第二次新增第二個if成立進入:

 

 不成立進入else

 

 先進入如圖if判斷,判斷上一個不為空的hash值與這個要新增的hash值是否相等,經過hash原始碼可知為相等並且,Object的equals方法比較的記憶體地址也相等,因為沒new物件,都在一個常量池中,所以成立把p賦給e:下一步進入

 

 因為e不為空(null),所以賦值給oldValue為一個常量PRESENT,返回給put,put返回給add:

 

 因為PRESENT不等於null,所以返回給objects.add("JAVA");的值為false:

 

 此時新增失敗,正好印證了HashSet不能新增重複元素的特性。

相關文章