HashMap的初始容量和加載因子

原文地址:https://xeblog.cn/articles/26

注:本文所有代碼示例均基于 JDK8拄踪。

從源碼出發(fā)

默認值

通過查看 HashMap 的源碼可以得知其默認的初始容量為 16散怖,默認的加載因子為 0.75

/**
 * The default initial capacity - MUST be a power of two.
 * 默認的初始容量(必須是2的N次冪)毒涧,默認為2^4=16
 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
 * The load factor used when none specified in constructor.
 * 默認的加載因子為0.75
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

構(gòu)造方法

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and load factor.
 *
 * @param  initialCapacity the initial capacity
 * @param  loadFactor      the load factor
 * @throws IllegalArgumentException if the initial capacity is negative
 *         or the load factor is nonpositive
 */
public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " +
                                                                                     initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
                initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new IllegalArgumentException("Illegal load factor: " +
                                                                                     loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
}

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and the default load factor (0.75).
 *
 * @param  initialCapacity the initial capacity.
 * @throws IllegalArgumentException if the initial capacity is negative.
 */
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

/**
 * Constructs an empty <tt>HashMap</tt> with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

一般情況下都是通過這三種構(gòu)造方法來初始化 HashMap 的呀打。通過默認的無參構(gòu)造方法初始化后 HashMap 的容量就是默認的16鉴分,加載因子也是默認的0.75;通過帶參數(shù)的構(gòu)造方法可以初始化一個自定義容量和加載因子的 HashMap惧蛹。通常情況下扇救,加載因子使用默認的0.75就好。

初始容量

HashMap 的容量要求必須是2的N次冪香嗓,這樣可以提高散列的均勻性迅腔,降低 Hash 沖突的風險。但是容量可以通過構(gòu)造方法傳入的靠娱,如果我傳入一個非2次冪的數(shù)進去呢沧烈?比如3?傳進去也不會干嘛呀饱岸,又不報錯掺出。。苫费。哈哈哈哈汤锨。
是的,不會報錯的百框,那是因為 HashMap 自己將這個數(shù)轉(zhuǎn)成了一個最接近它的2次冪的數(shù)闲礼。這個轉(zhuǎn)換的方法是 tableSizeFor(int cap)

/**
 * Returns a power of two size for the given target capacity.
 */
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;
}

這個方法會將傳入的數(shù)轉(zhuǎn)換成一個2次冪的數(shù),比如傳入的是3柬泽,則返回的是4慎菲;傳入12,則返回的是16锨并。

加載因子

加載因子和 HashMap 的擴容機制有著非常重要的聯(lián)系露该,它可以決定在什么時候才進行擴容。HashMap 是通過一個閥值來確定是否擴容第煮,當容量超過這個閥值的時候就會進行擴容解幼,而加載因子正是參與計算閥值的一個重要屬性,閥值的計算公式是 容量 * 加載因子包警。如果通過默認構(gòu)造方法創(chuàng)建 HashMap 撵摆,則閥值為 16 * 0.75 = 12 ,就是說當 HashMap 的容量超過12的時候就會進行擴容害晦。

/**
 * The next size value at which to resize (capacity * load factor).
 *
 * @serial
 */
int threshold;

這是 HashMapputVal(...) 方法的一個片段特铝,put(...) 方法其實就是調(diào)用的這個方法,size 是當前 HashMap 的元素個數(shù)壹瘟,當元素個數(shù)+1后超過了閥值就會調(diào)用 resize() 方法進行擴容鲫剿。

if (++size > threshold)
        resize();

加載因子在一般情況下都最好不要去更改它,默認的0.75是一個非忱睿科學的值牵素,它是經(jīng)過大量實踐得出來的一個經(jīng)驗值。當加載因子設(shè)置的比較小的時候澄者,閥值就會相應(yīng)的變小笆呆,擴容次數(shù)就會變多,這就會導致 HashMap 的容量使用不充分粱挡,還沒添加幾個值進去就開始進行了擴容赠幕,浪費內(nèi)存,擴容效率還很低询筏;當加載因子設(shè)置的又比較大的時候呢榕堰,結(jié)果又很相反,閥值變大了嫌套,擴容次數(shù)少了逆屡,容量使用率又提高了,看上去是很不錯踱讨,實際上還是有問題魏蔗,因為容量使用的越多,Hash 沖突的概率就會越大痹筛。所以莺治,選擇一個合適的加載因子是非常重要的廓鞠。

實踐檢驗真理

默認無參構(gòu)造方法測試

通過默認構(gòu)造方法創(chuàng)建一個 HashMap,并循環(huán)添加13個值

image

當添加第1個值后谣旁,容量為16床佳,加載因子為0.75,閥值為12

image

當添加完第13個值后榄审,執(zhí)行了擴容操作砌们,容量變?yōu)榱?2,加載因子不變瘟判,閥值變?yōu)榱?4

image

有參構(gòu)造方法測試-只設(shè)置初始容量

創(chuàng)建一個初始容量為12(非2次冪數(shù))的 HashMap怨绣,并添加1個值

image

創(chuàng)建一個初始容量為2的 HashMap,并添加2個值

image

當添加完第1個值后,容量為2,加載因子為0.75猎莲,閥值為1

image

當添加完第2個值后奔则,執(zhí)行了擴容操作,容量變?yōu)?未蝌,加載因子為0.75驮吱,閥值為3

image

有參構(gòu)造方法測試-設(shè)置初始容量和加載因子

創(chuàng)建一個初始容量為2、加載因子為1的 HashMap萧吠,并添加2個值

image

當添加完第1個值后左冬,容量為2,加載因子為1纸型,閥值為2

image

當添加完第2個值后拇砰,并沒有執(zhí)行擴容操作,容量狰腌、加載因子除破、閥值均沒有變化

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市琼腔,隨后出現(xiàn)的幾起案子瑰枫,更是在濱河造成了極大的恐慌,老刑警劉巖丹莲,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件光坝,死亡現(xiàn)場離奇詭異,居然都是意外死亡甥材,警方通過查閱死者的電腦和手機盯另,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來擂达,“玉大人土铺,你說我怎么就攤上這事胶滋。” “怎么了悲敷?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵究恤,是天一觀的道長。 經(jīng)常有香客問我后德,道長部宿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任瓢湃,我火速辦了婚禮理张,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绵患。我一直安慰自己雾叭,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布落蝙。 她就那樣靜靜地躺著织狐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筏勒。 梳的紋絲不亂的頭發(fā)上移迫,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音管行,去河邊找鬼厨埋。 笑死,一個胖子當著我的面吹牛捐顷,可吹牛的內(nèi)容都是我干的荡陷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼套菜,長吁一口氣:“原來是場噩夢啊……” “哼亲善!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起逗柴,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蛹头,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后戏溺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渣蜗,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年旷祸,在試婚紗的時候發(fā)現(xiàn)自己被綠了耕拷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡托享,死狀恐怖骚烧,靈堂內(nèi)的尸體忽然破棺而出浸赫,到底是詐尸還是另有隱情,我是刑警寧澤赃绊,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布既峡,位于F島的核電站,受9級特大地震影響碧查,放射性物質(zhì)發(fā)生泄漏运敢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一忠售、第九天 我趴在偏房一處隱蔽的房頂上張望传惠。 院中可真熱鬧,春花似錦稻扬、人聲如沸卦方。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愿汰。三九已至,卻和暖如春乐纸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摇予。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工汽绢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侧戴。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓宁昭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親酗宋。 傳聞我的和親對象是個殘疾皇子积仗,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容