HashMap源碼分析——put和get(一)

HashMap源碼分析——put和get(一)

前言

首先,這是自己的開的不知道多少個坑的筆記了(汗顏)蒲祈,這些筆記都是自己在Java這條道路上的初學(xué)階段所思所想,并沒有多少含金量~

想第一篇記一記HashMap,沒有為什么腔剂,任性。

首先驼仪,HashMap的基本方法應(yīng)該都知道了掸犬,put(key,value)以及get(key)袜漩。
另外值得注意的一個基礎(chǔ)問題是HashMap的key、value都不能是基本數(shù)據(jù)類型(即不能為byte short int long char float double boolean),但是很特別的一點是key和value可以為null

1. 慢著 開始之前復(fù)習(xí)下異或和右移運算符

1.1 異或的基本運算

異或是二元按位運算符的一種湾碎,最基本的概念是在當(dāng)前位下噪服,兩個二進制相同則為0,不同則為1

public static void main(String []args){
    int i = -5;
    int j = 5;
    System.out.println("i : " + Integer.toBinaryString(i));
    System.out.println("j : " + Integer.toBinaryString(j));
    System.out.println("i ^ j : " + Integer.toBinaryString(i ^ j));
    System.out.println("i ^ j : " + (i ^ j));
    /**
    *  output :
    *  i : 11111111111111111111111111111011
    *  j : 101
    *  i ^ j : 11111111111111111111111111111110
    *  i ^ j : -2
    */
}

1.2 異或規(guī)律

  • 0異或A結(jié)果都為A : 0 ^ 1 = 1 0 ^ 0 = 0
  • 1異或A結(jié)果都為A的相反數(shù) : 1 ^ 1 = 0 1 ^ 0 = 0
  • A異或A結(jié)果都為0

1.3 異或進階

關(guān)于異或進階不再贅述胜茧,大家可以觀看維基百科中的異或講解

值得一提的是面試經(jīng)常會考到:如何不使用第三個參數(shù)來交換a和b的值,這時候就可以使用異或仇味。

int a = 10;
int b = 41;
a = b ^ a;
b = b ^ a; // b = b ^ ( b ^ a) = a
a = a ^ b; // a = ( b ^ a ) ^ a = b

1.4 左移和右移運算符和它們的規(guī)律

左移和右移運算符是奇怪的運算操作符呻顽,我剛開始學(xué)的時候覺得不就是移位嘛,移位就是了丹墨,后來看《Java編程思想》的時候才知道原來左移和右移原來有這樣那樣的限制……

先從最簡單的開始說廊遍,左移就是低位補0,右移就是高位補符號位贩挣,無符號右移運算符就是高位補0(這里不再贅述)

接著 在一般情況下 左移和右移都有下面的規(guī)律 :

  • a << b = a * (2 ^ b)
  • a >> b = a / (2 ^ b)

例如 :

public static void main(String []args){
    int i = 5;
    int j = 32;
    int m = 40;
    System.out.println(3 << i);
    System.out.println(3 << j);
    System.out.println(3 << m);
    /**
    * output :
    * 96
    * 3
    * 768
    */
}

大家可能發(fā)現(xiàn)了喉前,有些結(jié)果好像與公式并不符合,這是因為int類型的“限制”

眾所周知王财,在Java中int占四個字節(jié)卵迂,也就是32位,在做移位操作時绒净,無論是左移還是右移见咒,右操作運算符都不能大于或者等于32(當(dāng)然,我說的是左邊的數(shù)值是int類型時)挂疆,因為一旦超過了32改览,左邊的數(shù)值完全變了個樣。就拿1 << 32而言:

1 << 32

我們發(fā)現(xiàn)1 << 32如果按照正常計算的話就會變成0缤言,更別提3 << 32宝当,5 << 91了,如果按照正常流程來的話胆萧,只要右操作數(shù)大于32庆揩,結(jié)果都變成了0,當(dāng)然跌穗,Java不可能這樣子計算盾鳞,它采取了一種聰明的操作方式,至于為什么瞻离,目前不在討論范圍只內(nèi)腾仅。另一種狀況是,如果恰巧將1移到了符號位上套利,即便移位之前是正的數(shù)字推励,也會變成負的鹤耍,就像1 << 31 = - 2147483648 那樣。所以验辞,在上邊說的公式有諸多的限制稿黄。

這種聰明的方式就是,在左操作數(shù)類型為int時跌造,當(dāng)右側(cè)數(shù)值大于等于32杆怕,都可以對右操作數(shù)取余操作( % 32),然后再做移位運算壳贪,例如:

3 << 40 = 3 << (40 % 32) = 3 << 8 = 3 * (2 ^ 8) = 768

以上都說的是int類型下的移位操作陵珍,如果左邊操作數(shù)為char、byte违施、short類型都會被轉(zhuǎn)換成int類型處理互纯,當(dāng)左操作數(shù)是long的時候,右邊操作數(shù)的最大限制變成了64磕蒲。

2. HashMap

2.1 從HashMap結(jié)構(gòu)說起

HashMap結(jié)構(gòu)如下圖所示:

HashMap結(jié)構(gòu)

總的來說留潦,HashMap的結(jié)構(gòu)是:數(shù)組+鏈表+紅黑樹 (PS : 我用的是8版本的)

HashMap中鏈表的節(jié)點
節(jié)點組成的數(shù)組
紅黑二叉樹

目前,現(xiàn)將紅黑二叉樹看成是一個不一般的二叉樹吧(我能說現(xiàn)階段不知道什么是紅黑二叉樹嘛XD)辣往。以上三張圖分別就是組成HashMap的三種數(shù)據(jù)結(jié)構(gòu)了兔院。

然后,再來看一下幾個HashMap中幾個重要的字段 :

/**
* 默認的數(shù)組容量(也就是數(shù)組的長度) —— 數(shù)字必須是二次冪
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 數(shù)組的最大容量
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 當(dāng)使用無參構(gòu)造函數(shù)時 默認的加載因子
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
 * 當(dāng)某個數(shù)組下的鏈表長度超過8時 鏈表將會轉(zhuǎn)換為紅黑樹
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 當(dāng)節(jié)點的數(shù)量超過threshold時會發(fā)生擴容 此外 當(dāng)尚未初始化數(shù)組的時候站削,這個字段也會存放初始數(shù)組的容量秆乳,如果是0的話表示容量是默認的數(shù)組容量(16)
*/
int threshold;

什么是加載因子?我搜索了百度钻哩,然后一臉懵逼屹堰,它是這樣介紹的:

加載因子是表示Hsah表中元素的填滿的程度。

一臉懵逼街氢,兩臉茫然扯键,然后,在進行相關(guān)搜索珊肃,發(fā)現(xiàn)這個比較靠譜

threshold(閾值) = (int)加載因子 * 數(shù)組容量

還是有點懵逼H傩獭!伦乔!意思就是說當(dāng) 節(jié)點數(shù)量 > 數(shù)組容量 * 加載因子時厉亏,數(shù)組會擴容.

我們來驗證一下吧!烈和!

2.2 HashMap的構(gòu)造函數(shù)

我們通過idea發(fā)現(xiàn)HashMap有四種構(gòu)造函數(shù)爱只,先看前三種(畢竟最后一種不是重點):

    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    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);
    }
  • 無參構(gòu)造函數(shù) : 設(shè)置了加載因子為默認加載因子(0.75f)

    PS 再來回顧下加載因子是干嘛的:加載因子是擴容用的 什么時候該擴容呢?就是節(jié)點個數(shù)大于加載因子??數(shù)組長度的時候就該擴容了

  • 一個參數(shù)的構(gòu)造函數(shù) : 設(shè)置了容量初始容量招刹,然后在源碼里面直接this交給了第三個構(gòu)造參數(shù)處理

  • 兩個參數(shù)的構(gòu)造函數(shù) : 設(shè)置了初始容量以及加載因子恬试,我發(fā)現(xiàn)在這個構(gòu)造函數(shù)中好像并沒有關(guān)于數(shù)組初始容量的更多限制啊窝趣,剛才源碼中不是說初始容量必須是二次冪嗎?我傳一個13训柴,19哑舒,在這個構(gòu)造參數(shù)中也沒拋出異常啊!!不急,我們看最后一句 :

this.threshold = tableSizeFor(initialCapacity);

我們傳入的初始容量13幻馁,18洗鸵,41……這些“不規(guī)范的”(也就是不是二次冪的)數(shù)字傳給了tableSizeFor這個函數(shù),最終返回給了threshold這個變量中(別忘了仗嗦,這個變量除了可以記錄“擴張閾值”膘滨,在數(shù)組還沒有初始化的時候還可以存放數(shù)組的自定義容量,這些都是注釋中所標(biāo)注的東西)儒将。來領(lǐng)略一下tableSizeFor的真正魅力,這個函數(shù)可以 :

把任何一個int類型的对蒲、大于0的數(shù)字轉(zhuǎn)成一個與之相近并大于這個數(shù)字的二次冪整數(shù)

聽上去有點繞口钩蚊,簡單點說15進去了成了16,17進去了出來搖身一變成了32(比17大的最小二次冪整數(shù)就是32了)蹈矮,非常神奇的一個函數(shù)砰逻,第二小篇接著看這個函數(shù)。

下一小節(jié) : HashMap源碼分析——put和get(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泛鸟,一起剝皮案震驚了整個濱河市蝠咆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌北滥,老刑警劉巖刚操,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異再芋,居然都是意外死亡菊霜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門济赎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鉴逞,“玉大人,你說我怎么就攤上這事司训」辜瘢” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵壳猜,是天一觀的道長勾徽。 經(jīng)常有香客問我,道長统扳,這世上最難降的妖魔是什么捂蕴? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任譬涡,我火速辦了婚禮,結(jié)果婚禮上啥辨,老公的妹妹穿的比我還像新娘涡匀。我一直安慰自己,他們只是感情好溉知,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布陨瘩。 她就那樣靜靜地躺著,像睡著了一般级乍。 火紅的嫁衣襯著肌膚如雪舌劳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天玫荣,我揣著相機與錄音甚淡,去河邊找鬼。 笑死捅厂,一個胖子當(dāng)著我的面吹牛贯卦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播焙贷,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼撵割,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辙芍?” 一聲冷哼從身側(cè)響起啡彬,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎故硅,沒想到半個月后庶灿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡吃衅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年跳仿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捐晶。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡菲语,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惑灵,到底是詐尸還是另有隱情山上,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布英支,位于F島的核電站佩憾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妄帘,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一楞黄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抡驼,春花似錦鬼廓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至馏锡,卻和暖如春雷蹂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杯道。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工匪煌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人党巾。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓萎庭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昧港。 傳聞我的和親對象是個殘疾皇子擎椰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法支子,類相關(guān)的語法创肥,內(nèi)部類的語法,繼承相關(guān)的語法值朋,異常的語法叹侄,線程的語...
    子非魚_t_閱讀 31,625評論 18 399
  • HashMap 源碼分析 前幾篇分析了 ArrayList , LinkedList 昨登,Vector 趾代,Stack...
    醒著的碼者閱讀 2,842評論 4 44
  • 前言 HashMap HashMap類繼承圖 HashMap屬性 HashMap構(gòu)造函數(shù)HashMap(int i...
    HikariCP閱讀 1,900評論 0 5
  • 創(chuàng)建文件 os.mknod(“test.txt”) 創(chuàng)建空文件 open(“test.txt”,w) 直接打開一個...
    咸魚而已閱讀 307評論 0 0
  • 三亞是海南的一個小城撒强,夏天陽光明媚,全部都是海笙什,那里景色宜人飘哨,物產(chǎn)豐富,是個美麗的地方琐凭。 三亞一帶的海面時而平靜芽隆,...
    叫我公主寶寶閱讀 277評論 0 0