HashSet/HashMap儲存過程、擴容、實現原理
論壇可以幫助程式設計師很快的提升自己,
第一次看見這句話不以為然,因為多多少少逛過,感覺並沒有對自己多大幫助
慢慢逛論壇次數多了,感覺自己只是在打發時間,根本對自己沒有任何幫助。突發奇想不再逛首頁,而是通過各大板塊選自己最近學的知識來檢驗自己的學習。
------------------------------------------------------分割線-------------------------------------------------------
還好,發現了不錯的論壇,比如
Surrin1999發出的 關於HashSet的有序無序問題
nayi_224回覆的見解真的很到位,多的不說,
------------------------------------------------------分割線-------------------------------------------------------以下藍色字為JDK原始碼
HashSet是基於HashMap儲存的資料,結構是陣列 + 連結串列
預設容量static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
載入因子(用來擴容的) static final float DEFAULT_LOAD_FACTOR = 0.75f;
在底層儲存資料時,較為形象的畫出如下圖:
儲存過程:
擴容是在當前容量的基礎上增加一倍(newCap = oldCap << 1),在不超過最大容量 的前提下 static final int MAXIMUM_CAPACITY = 1 << 30; // 1073741824
關於載入因子:
載入因子過小,會導致記憶體的浪費,也會導致rehash操作頻繁,降低效率
載入因子過大,會導致每個桶中的連結串列過長從而降低效率
從JDK1.8開始,為了減小擴容次數,同時也為了保證每一個桶中的查詢效率,在桶中元素超過8時(static final int TREEIFY_THRESHOLD = 8;),
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 注意下標從0開始
treeifyBin(tab, hash);
關於紅黑樹,本人比較愚笨,不懂了。。。
關於指定初始容量:
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY : n + 1;
}
以上是JDK中原始碼,計算結果可以藉助IDE進行,只需每次修改n結束後輸出即可,結論是:
指定初始容量X時,並且 2n-1 < x <=2n 那麼最終該集合的容量為2n。