日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

hashmap底层原理_Java集合 - HashMap原理(一) 概念和底层架构

發(fā)布時間:2025/3/19 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hashmap底层原理_Java集合 - HashMap原理(一) 概念和底层架构 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

HashMap在Java開發(fā)中使用的非常頻繁,可以說僅次于String,可以和ArrayList并駕齊驅(qū),準(zhǔn)備用幾個章節(jié)來梳理一下HashMap。我們還是從定義一個HashMap開始。

HashMap mapData = new HashMap<>();

我們從此處進(jìn)入源碼,逐步揭露HashMap

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

我們發(fā)現(xiàn)了兩個變量loadFactor和DEFAULT_LOAD_FACTOR,從命名方式來看:因為沒有接收到loadFactor參數(shù),從而將某個默認(rèn)值賦值給了loadFactor。這兩變量到底是什么意思,還有無其他變量?

其實HashMap中定義的靜態(tài)變量和成員變量很多,我們看一下

//靜態(tài)變量static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16static final int MAXIMUM_CAPACITY = 1 << 30;static final float DEFAULT_LOAD_FACTOR = 0.75f;static final int TREEIFY_THRESHOLD = 8;static final int UNTREEIFY_THRESHOLD = 6;static final int MIN_TREEIFY_CAPACITY = 64;//成員變量transient Node[] table;transient Set> entrySet;transient int size;transient int modCount;int threshold;final float loadFactor;

共有6個靜態(tài)變量,都設(shè)置了初始值,且被final修飾,叫常量更合適,它們的作用其實也能猜出來,就是用于成員變量的默認(rèn)值設(shè)定以及方法中相關(guān)的條件判斷等情況。

共有6個成員變量,除這些成員變量外,還有一個重要概念capacity,我們主要說一下table,entrySet,capacity, size,threshold,loadFactor,我們我們簡單解釋一下它們的作用。

1. table變量

table變量為HashMap的底層數(shù)據(jù)結(jié)構(gòu),用于存儲添加到HashMap中的Key-value對,是一個Node數(shù)組,Node是一個靜態(tài)內(nèi)部類,一種數(shù)組和鏈表相結(jié)合的復(fù)合結(jié)構(gòu),我們看一下Node類:

static class Node implements Map.Entry { final int hash; final K key; V value; Node next; Node(int hash, K key, V value, Node next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entry,?> e = (Map.Entry,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; }}

若以乘機做比喻的話,那么你買票的身份證號就是(key),通過hash算法生成的(hash)值就相當(dāng)于值機后得到的航班座位號;你自己自然就是(value),你旁邊的座位、人就是下一個Node(next);這樣的一個座位整體(包括所坐人員及其身份證號、座位號)就是一個table,這許多的table的構(gòu)建的Node[] table,就構(gòu)成了本次航班任務(wù)。

那么為什么要用到數(shù)組和鏈表結(jié)合的數(shù)據(jù)結(jié)構(gòu)?

我們知道數(shù)組和鏈表都有其各自的優(yōu)點和缺點,數(shù)組連續(xù)存儲,尋址容易,插入刪除操作相對困難;而鏈表離散存儲,尋址相對困難,而插入刪除操作容易;而HashMap結(jié)合了這兩種數(shù)據(jù)結(jié)構(gòu),保留了各自的優(yōu)點,又彌補了各自的缺點,當(dāng)然鏈表長度太長的話,在JDK8中會轉(zhuǎn)化為紅黑樹,紅黑樹在后面的TreeMap章節(jié)在講解。

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

怎么解釋這種結(jié)構(gòu)呢?

還是以乘機為例來說明,假如購票系統(tǒng)比較人性化并取消了值機操作,購票按照年齡段進(jìn)行了區(qū)分,方便大家旅途溝通交流,于是20歲以下共6個人的分為了一組在20A20F,2030歲共6個人分為一組在21A21F,3040歲共6個人分為一組在22A22F,4050歲共6個人分為一組在23A~23F。

這時我們?nèi)绻?0幾歲的小姐姐,我們很容易知道去21排找,從21A開始往下找,應(yīng)該就能很快找到。

從數(shù)據(jù)的角度看,按年齡段分組(通過hash算法得到hash值,不同年齡段hash值不同,相同年齡段hash值相同)后,將各年齡段中第一個坐到座位上的人放到數(shù)組table中,下一個人來的時候,將第一個人往里面挪,自己在數(shù)組里,并將next指向第一個人。

2. entrySet變量

entrySet變量為EntrySet實體,定義為變量可保證不重復(fù)多次創(chuàng)建,是一個Map.Entry的集合,Map.Entry是一個接口,Node類就實現(xiàn)了該接口,因此EntrySet中方法需要操作的數(shù)據(jù)就是HashMap的Node實體。

public Set> entrySet() { Set> es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}

3. capacity

capacity并不是一個成員變量,但HashMap中很多地方都會使用到這個概念,意思是容量,很好理解,在前面的文中提到了兩個常量都與之相關(guān)

/** * The default initial capacity - MUST be a power of two(必須為2的冪次). * 默認(rèn)容量16,舉例:飛機上正常的座位所對應(yīng)的人員數(shù)量, */static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30(必須為2的冪次,且不能大于最大容量1,073,741,824). * 舉例:緊急情況下,如救災(zāi)時盡可能快撤離人員,這個時候在保證安全的情況下(允許站立),能運輸?shù)娜藛T數(shù) */static final int MAXIMUM_CAPACITY = 1 << 30;

同時HashMap還具有擴(kuò)容機制,容量的規(guī)則為2的冪次,即capacity可以是1,2,4,8,16,32...,怎么實現(xiàn)這種容量規(guī)則呢?

/** * 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;}

用該方法即可找到傳遞進(jìn)來的容量的最近的2的冪次,即

cap = 2, return 2;

cap = 3, return 4;

cap = 9, return 16;

...

大家可以傳遞值進(jìn)去自己算一下,先cap-1操作,是因為當(dāng)傳遞的cap本身就是2的冪次情況下,假如為4,不減去一最后得到的結(jié)果將是傳遞的cap的2倍。

我們來一行行計算一下:tableSizeFor(11),按規(guī)則最后得到的結(jié)果應(yīng)該是16

//第一步:n = 10,轉(zhuǎn)為二進(jìn)制為00001010int n = cap - 1;//第二步:n右移1位,高位補0(10進(jìn)制:5,二進(jìn)制:00000101),并與n做或運算(有1為1,同0為0),然后賦值給n(10進(jìn)制:15,二進(jìn)制:00001111)n |= n >>> 1;//第三步:n右移2位,高位補0(10進(jìn)制:3,二進(jìn)制:00000011),并與n做或運算(有1為1,同0為0),然后賦值給n(10進(jìn)制:15,二進(jìn)制:00001111)n |= n >>> 2;//第四步:n右移4位,高位補0(10進(jìn)制:0,二進(jìn)制:00000000),并與n做或運算(有1為1,同0為0),然后賦值給n(10進(jìn)制:15,二進(jìn)制:00001111)n |= n >>> 4;//第五步:n右移8位,高位補0(10進(jìn)制:0,二進(jìn)制:00000000),并與n做或運算(有1為1,同0為0),然后賦值給n(10進(jìn)制:15,二進(jìn)制:00001111)n |= n >>> 8;//第六步:n右移16位,高位補0(10進(jìn)制:0,二進(jìn)制:00000000),并與n做或運算(有1為1,同0為0),然后賦值給n(10進(jìn)制:15,二進(jìn)制:00001111)n |= n >>> 16;//第七步:return 15+1 = 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;

最終的結(jié)果正如預(yù)期,算法很牛逼啊,ヽ(ー_ー)ノ,能看懂,但卻設(shè)計不出來。

4. size變量

size變量記錄了Map中的key-value對的數(shù)量,在調(diào)用putValue()方法以及removeNode()方法時,都會對其造成改變,和capacity區(qū)分一下即可。

5. threshold變量和loadFactor變量

threshold為臨界值,顧名思義,當(dāng)過了臨界值就需要做一些操作了,在HashMap中臨界值“threshold = capacity * loadFactor”,當(dāng)超過臨界值時,HashMap就該擴(kuò)容了。

loadFactor為裝載因子,就是用來衡量HashMap滿的程度,默認(rèn)值為DEFAULT_LOAD_FACTOR,即0.75f,可通過構(gòu)造器傳遞參數(shù)調(diào)整(0.75f已經(jīng)很合理了,基本沒人會去調(diào)整它),很好理解,舉個例子:

100分的試題,父母只需要你考75分,就給你買一臺你喜歡的電腦,裝載因子就是0.75,75分就是臨界值;如果幾年后,試題的分?jǐn)?shù)變成200分了,這個時候就需要你考到150分才能得到你喜歡的電腦了。

總結(jié)

本文主要講解了HashMap中的一些主要概念,同時對其底層數(shù)據(jù)結(jié)構(gòu)從源碼的角度進(jìn)行了分析,table是一個數(shù)據(jù)和鏈表的復(fù)合結(jié)構(gòu),size記錄了key-value對的數(shù)量,capacity為HashMap的容量,其容量規(guī)則為2的冪次,loadFactor為裝載因此,衡量滿的程度,而threshold為臨界值,當(dāng)超出臨界值時就會擴(kuò)容。


----------------------------------------------------

轉(zhuǎn)載自:https://www.cnblogs.com/LiaHon/p/11142958.html

總結(jié)

以上是生活随笔為你收集整理的hashmap底层原理_Java集合 - HashMap原理(一) 概念和底层架构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。