讀讀HashMap源碼

幾個重要的變量:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//初始大小

static final int MAXIMUM_CAPACITY = 1 << 30;//map中最多可以容納的數(shù)量

static final float DEFAULT_LOAD_FACTOR = 0.75f; //與當(dāng)前容量大小決定擴(kuò)容極限值各吨,如默認(rèn)的容量(16),默認(rèn)的擴(kuò)容極限值(16 * 0.75 = 12)啃洋;如果size達(dá)到12時,進(jìn)行下次擴(kuò)容篡悟,容量和極限值均擴(kuò)容成原來的兩倍致板,32,24;


構(gòu)造方法

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);
    }

public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

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

put(K key, V value)

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

//對key進(jìn)行hash
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}


transient Node<K,V>[] table;    //Node是單向鏈表的節(jié)點(diǎn)坊夫,When allocated, length is always a power of two.
// @return previous value, or null if none
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;    //resize(): Initializes or doubles table size.此處時初始化
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);   //如果目標(biāo)index目前的元素是空的則直接賦值就行
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;  //key已存在map中砖第,更新值
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);   //以鏈表的形式將同一index的數(shù)據(jù)組織起來
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }


final Node<K, V>[] resize() {
   ...
     //初始大小為static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
     //計(jì)算得出新數(shù)組的大小撤卢,成倍增長 newThr = oldThr << 1
     //如果達(dá)到MAXIMUM_CAPACITY,其他不變梧兼,threshold = Integer.MAX_VALUE放吩,return原數(shù)組
     Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab; //更新成員變量的值
   ...
    //將舊數(shù)組的數(shù)據(jù)按序遷移至新數(shù)組
     
}

put方法中含有的信息較多,可以看到HashMap內(nèi)部是數(shù)組+鏈表的形式來存儲數(shù)據(jù)的羽杰,每個數(shù)據(jù)被組裝成鏈表的節(jié)點(diǎn)渡紫。


get(Object key)

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {    //取到數(shù)組中對應(yīng)index的鏈表的首節(jié)點(diǎn)
            if (first.hash == hash && // 從首節(jié)點(diǎn)開始遍歷取出目標(biāo)元素
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

如果判斷元素是否是目標(biāo)元素:node.hash == hash && node.key == key || (key != null && key.equals(k))


remove(Object key)

public boolean remove(Object key, Object value) {
        return removeNode(hash(key), key, value, true, true) != null;
    }
//return the node, or null if none
final Node<K,V> removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
        Node<K,V>[] tab; Node<K,V> p; int n, index;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {    //通過hash快速找到對應(yīng)的index
            Node<K,V> node = null, e; K k; V v;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            else if ((e = p.next) != null) {
                if (p instanceof TreeNode)
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }   //遍歷index中的鏈表元素,找到目標(biāo)節(jié)點(diǎn)
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                if (node instanceof TreeNode)
                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                else if (node == p)
                    tab[index] = node.next;
                else
                    p.next = node.next;
                ++modCount;
                --size;
                afterNodeRemoval(node);
                return node;
            }//將目標(biāo)節(jié)點(diǎn)從鏈表中移除
        }
        return null;
    }

replace(K key, V value)

public V replace(K key, V value) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) != null) {
            V oldValue = e.value;
            e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
        return null;
    }

//well考赛,主要分析下面這個方法
public boolean replace(K key, V oldValue, V newValue) {
        Node<K,V> e; V v;
            //getNode()在get()方法中分析過了
        if ((e = getNode(hash(key), key)) != null &&
            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
            e.value = newValue; //替換目標(biāo)節(jié)點(diǎn)的值
            afterNodeAccess(e);
            return true;
        }
        return false;
    }

clear()

public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;  //清空數(shù)組即可
        }
    }

Q:為什么擴(kuò)容因子是0.75惕澎?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市欲虚,隨后出現(xiàn)的幾起案子集灌,更是在濱河造成了極大的恐慌,老刑警劉巖复哆,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欣喧,死亡現(xiàn)場離奇詭異,居然都是意外死亡梯找,警方通過查閱死者的電腦和手機(jī)唆阿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锈锤,“玉大人驯鳖,你說我怎么就攤上這事【妹猓” “怎么了浅辙?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長阎姥。 經(jīng)常有香客問我记舆,道長,這世上最難降的妖魔是什么呼巴? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任泽腮,我火速辦了婚禮,結(jié)果婚禮上衣赶,老公的妹妹穿的比我還像新娘诊赊。我一直安慰自己,他們只是感情好府瞄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布碧磅。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪续崖。 梳的紋絲不亂的頭發(fā)上敲街,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音严望,去河邊找鬼。 笑死逻恐,一個胖子當(dāng)著我的面吹牛像吻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播复隆,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拨匆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挽拂?” 一聲冷哼從身側(cè)響起惭每,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亏栈,沒想到半個月后台腥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绒北,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年黎侈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闷游。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡峻汉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出脐往,到底是詐尸還是另有隱情休吠,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布业簿,位于F島的核電站瘤礁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辖源。R本人自食惡果不足惜蔚携,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望克饶。 院中可真熱鬧酝蜒,春花似錦、人聲如沸矾湃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至霉咨,卻和暖如春蛙紫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背途戒。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工坑傅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喷斋。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓唁毒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親星爪。 傳聞我的和親對象是個殘疾皇子浆西,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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