//預設初始容量 2^4 16//hashmap 底層陣列的長度總是 2 的 n 次方,這一點可參看後面關於 hashmap 構造器的介紹;
//當length 總是 2 的倍數時,h & (length-1)將是乙個非常巧妙的設計:假設 h=5,length=16, 那麼 h & length - 1 將得到 5;
//如果 h=6,length=16, 那麼 h & length - 1 將得到 6 ……如果 h=15,length=16, 那麼 h & length - 1 將得到 15;
//但是當 h=16 時 , length=16 時,那麼 h & length - 1 將得到 0 了;當 h=17 時 , length=16 時
//那麼 h & length - 1 將得到 1 了……這樣保證計算得到的索引值總是位於 table 陣列的索引之內
static final int default_initial_capacity = 1 << 4; // aka 16
//容量最大值 2^30
static final int maximum_capacity = 1 << 30;
//預設載入因子0.75;當表中超過75%的位置已經填入元素,這個表就會用雙倍的桶數自動地進行;結合時間和空間效率考慮得到的乙個折中方案
static final float default_load_factor = 0.75f;
//鍊錶轉為紅黑樹的閥值;當桶內鍊錶節點數》8;就會將桶內資料結構從鍊錶轉為紅黑樹
static final int treeify_threshold = 8;
//進行resize;當<6時;紅黑樹轉為鍊錶;
static final int untreeify_threshold = 6;
//最小樹形化容量閥值,為了避免進行擴容、樹形化選擇的衝突
//min_treeify_capacity出現在了treeifybin()中,避免了在treeifybin()前判斷capacity與min_treeify_capacity比較的**量過大
static final int min_treeify_capacity = 64;
//在第一次使用時初始化node陣列,桶物件陣列
transient node table;
//當被呼叫entryset時被賦值。通過keyset()方法可以得到map key的集合,通過values方法可以得到map value的集合
transient set> entryset;
//該hashmap中共有多少個鍵值對
transient int size;
//當前 hashmap 修改的次數,這個變數用來保證 fail-fast 機制
transient int modcount;
//閾值 下次需要擴容時的值,等於 容量*載入因子;threshold = capacity * load factor
int threshold;
//載入因子,預設得載入因子也是在建構函式裡要賦值給這個得
final float loadfactor;
public hashmap(int initialcapacity, float loadfactor)//get方法
總的來講就是
1.判斷表是否為空或者待查詢的桶不為空
2.首先檢查待查詢的桶的第乙個元素是否是要找的元素,如果是直接返回
3.桶內紅黑樹,則呼叫gettreenode()查詢紅黑樹
4.桶內是鍊錶,遍歷鍊錶尋找節點
public v get(object key) while ((e = e.next) != null);}}
return null;
}//put方法
總的來講 就是
1.如果表為空或者表的長度為0,呼叫resize初始化表,為表分配空間2.二次雜湊處的桶為空,直接插入元素;
3.桶不為空,桶處的第乙個節點與待插入節點的雜湊相同且key「相等」,直接賦給變數e,桶中是紅黑樹,
呼叫puttreeval插入紅黑樹中,桶中是鍊錶,遍歷鍊錶,如果其中存在相同的key,則賦給變數e;不存
在則尾插法加入鍊錶,並判斷節點數是否大於8,如果大於8則呼叫treeifybin()轉化為紅黑樹
4.e不為空,替換其中的value值,並返回舊的value值,e為空,表大小+1,判斷是否達到了閾值,如果達到了則需要擴容
public v put(k key, v value)
final node resize()// 新的閾值是舊的兩倍 double threshold 且容量也為舊的兩倍
else if ((newcap = oldcap << 1) < maximum_capacity &&
oldcap >= default_initial_capacity)
newthr = oldthr << 1; // double threshold
}// 如果舊容量<=0 而舊閾值》0,陣列的新容量設定為老陣列擴容的閾值
// 這個應該使用的是帶引數的建構函式(這個已經將閾值弄為2的次方了(使用tablesizefor方法),所以不用擔心容量不為2的次方了)
else if (oldthr > 0) // initial capacity was placed in threshold
newcap = oldthr;
// 這裡是舊容量<=0 且舊閾值<=0 舊閾值<=0,代表使用的預設不帶引數的建構函式 // 第一次初始化雜湊表的操作到oldtab != null之前
else
if (newthr == 0)
// 這裡回答了為什麼閾值之前不是容量和載入因子的乘積了,在resize初始化table時會重新賦值
threshold = newthr;
@suppresswarnings()
node newtab = (node)new node[newcap];
table = newtab;
// 將舊雜湊表複製到新雜湊表中
if (oldtab != null)
else
} while ((e = next) != null);
// 將分組後的鍊錶對映到新桶中
if (lotail != null)
if (hitail != null) }}
}}return newtab;
}小弟不才,這是hashmap 訪問值的部分原理剖析;後續有補充再加上
JDK 1 8 HashMap擴容原理
擴容前計算索引 1010 0101 0000 1111 0000 0101 索引結果 5擴容以後容量是n 32 對應的二進位制是0001 1111 node本身的hash值是不變的,仍然是1010 0101,那麼擴容後node 的索引的計算是通過如下方式得到 擴容後計算索引 1010 0101 00...
JDK1 8 HashMap原始碼解析
普通常量 儲存node鍊錶的陣列 transient node table 由node節點構成的set集合 transient set entryset hashmap儲存元素的數量 transient int size 記錄hashmap結構性變化的次數 value覆蓋不算 和fail fast機...
JDK 1 8 HashMap原始碼解析
put方法分析 public v put k key,v value hash方法解析 減少hash衝突 static final int hash object key putval方法具體實現 final v putval int hash,k key,v value,boolean onlyi...