HashMap源碼之構(gòu)造函數(shù)--JDK1.8

構(gòu)造函數(shù)

變量解釋

  1. capacity杆融,表示的是hashmap中桶的數(shù)量楞卡,初始化容量initCapacity為16,第一次擴(kuò)容會(huì)擴(kuò)到64脾歇,之后每次擴(kuò)容都是之前容量的2倍蒋腮,所以容量每次都是2的次冪
  2. loadFactor,負(fù)載因子藕各,衡量hashmap一個(gè)滿的程度池摧,初始默認(rèn)為0.75
  3. threshold,hashmap擴(kuò)容的一個(gè)標(biāo)準(zhǔn)激况,每當(dāng)size大于這個(gè)標(biāo)準(zhǔn)時(shí)就會(huì)進(jìn)行擴(kuò)容操作,threeshold等于capacity*loadfacfactor

HashMap(int initialCapacity, float loadFactor)

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegalinitial 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);
}
//構(gòu)造函數(shù)前面都很容易理解作彤,無非是設(shè)置正確的initialCapacity和loadFactor
//最后一行調(diào)用的tableSizeFor(initialCapacity);如下
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;
    }
    

tableSizeFor(...)方法的作用在于找到大于等于initialCapacity的最小的2的冪。n右移一位再同自身進(jìn)行或操作使得n的最高位和最高位的下一位都為1.

n |= n >>> 1;
比如n=9乌逐,則n=1001(2)竭讳,n-1=100
1001
0100
-----
1100
這是因?yàn)榛虿僮鞯囊鬄橄嗤簧现灰嬖?則結(jié)果為1,全為0結(jié)果才為0.一個(gè)數(shù)最高位為1黔帕,右移一位后的數(shù)最高位也為1代咸,不論相對(duì)應(yīng)的位上另一個(gè)數(shù)是多少結(jié)果依舊為1.

而對(duì)于n |= n >>> 2n的最高位及其下一位都為1,右移兩位后再進(jìn)行或操作將使得得到的n的前4位都為1成黄,類似的n |= n >>> 4使得前8位為1呐芥,n |= n >>> 8使得前16位為1。當(dāng)然并不是說該方法調(diào)用下來就會(huì)使得返回的值是一個(gè)32位都為1的數(shù)字奋岁,這是因?yàn)楫?dāng)右移的位數(shù)操作實(shí)際的有效位數(shù)后是不會(huì)對(duì)數(shù)字產(chǎn)生任何變化的思瘟。

以n=9為例,在進(jìn)過兩次右移后n=1111(2)
00000000000000000000000000001111 n (int 32位)
00000000000000000000000000000000 n>>>4
--------------------------------
00000000000000000000000000001111
當(dāng)n右移4位后全部變成了0,使得結(jié)果不會(huì)發(fā)生任何變化闻伶,后面的n |= n >>> 8等等也一樣

在最后返回的時(shí)候做了一個(gè)判斷(n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1滨攻,正常來說返回的是一個(gè)n+1,在前面的操作中已經(jīng)將前幾位有效的數(shù)字變成了1(n=1111),這里加1使得n=10000(2)光绕,即變?yōu)榇笥诘扔趇nitialCapacity的最小的2的冪女嘲,到這里貌似就差不多了,但是在tableSizeFor(...)方法的第一句有一個(gè)減法操作int n = cap - 1;這是為什么呢诞帐?這里減1實(shí)際上是為處理傳入的數(shù)本身就是2的冪的情況欣尼。比如我傳入的是n=8=1000(2),如果不進(jìn)行減1操作停蕉,得到的則是n=10000(2)=16愕鼓,實(shí)際上我需要的就是8.

HashMap(Map<? extends K, ? extends V> m)

public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

這個(gè)構(gòu)造函數(shù)主要是用一個(gè)已有的map來構(gòu)造一個(gè)新的HashMap,這里主要在于putMapEntries(m, false);中慧起。

final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

前面幾行是做容錯(cuò)判斷菇晃,當(dāng)table沒有初始化或者傳入的map容量大于當(dāng)前map的閾值(threshold),都需要重新進(jìn)行設(shè)置蚓挤。從for循環(huán)開始則是將傳入的map的值插入到當(dāng)前map中磺送。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屈尼,隨后出現(xiàn)的幾起案子册着,更是在濱河造成了極大的恐慌拴孤,老刑警劉巖脾歧,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異演熟,居然都是意外死亡鞭执,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門芒粹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兄纺,“玉大人,你說我怎么就攤上這事化漆」来啵” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵座云,是天一觀的道長(zhǎng)疙赠。 經(jīng)常有香客問我,道長(zhǎng)朦拖,這世上最難降的妖魔是什么圃阳? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮璧帝,結(jié)果婚禮上捍岳,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好锣夹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布页徐。 她就那樣靜靜地躺著,像睡著了一般银萍。 火紅的嫁衣襯著肌膚如雪泞坦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天砖顷,我揣著相機(jī)與錄音贰锁,去河邊找鬼。 笑死滤蝠,一個(gè)胖子當(dāng)著我的面吹牛豌熄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播物咳,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锣险,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了览闰?” 一聲冷哼從身側(cè)響起芯肤,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎压鉴,沒想到半個(gè)月后崖咨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡油吭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年击蹲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婉宰。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歌豺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出心包,到底是詐尸還是另有隱情类咧,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布蟹腾,位于F島的核電站痕惋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岭佳。R本人自食惡果不足惜血巍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望珊随。 院中可真熱鬧述寡,春花似錦柿隙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至螟炫,卻和暖如春波附,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昼钻。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工掸屡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人然评。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓仅财,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親碗淌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盏求,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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